RE: Implementation of type classes

1999-09-12 Thread Heribert Schuetz

Hi Mark,

thanks a lot for the private lesson. I have downloaded various papers
and started to read them. I'm just done with the Wadler/Blott paper.

I already suspected that I was partly reinventing the wheel with my
translation of type classes. It turned out that my approach is exactly
the same as the Wadler/Blott translation. I didn't expect my approach to
be so close to the "standard" solution, but now this gives me the good
feeling that I might have understood the stuff. In hindsight the reason
for the close similarity is of course the "user-level" understanding
that I had of type classes before.

You were mentioning rank-2 polymorphism in your message. It was exactly
that beast (and also second-order lambda calculus) that I was afraid of
when I was unsure whether my transformation does its job. I feared that
these beasts (which I don't understand yet, but hope to after working
through the pile of downloaded papers) were indispensable for type
classes. Now I see that they are not, at least for the basic case.

Regards,

Heribert.


PS: What I meant with "dependent types" were the ideas in Cayenne.





RE: Implementation of type classes

1999-09-11 Thread Mark P Jones

Hi Heribert,

| The idea is that for every class assertion in the type of a variable,
| the variable gets an additional parameter that will be instantiated by a
| value representing the appropriate instance declaration. These values
| are tuples (let's call them "instance tuples") containing
| - one component for every superclass (viz. an instance tuple) and
| - one component for every class method (viz. a function with an
|   additional argument expecting the instance tuple)

This is exactly the scheme proposed by Wadler and Blott in their paper
"How to make ad-hoc polymorphism less ad-hoc"!  The things that you've
called "instance tuples" here are more commonly referred to as
"dictionaries", and so the translation that is used to implement
overloading by adding these extra dictionary parameters is known as
the "dictionary passing translation".  It is also the implementation
technique used in all current Haskell compilers/interepreters, as far
as I'm aware.  I'm not particularly proud of them, and they weren't
the main topic, but you can find a couple of chapters, going into
many of the gory details of all this in my thesis (Chaps. 7 and 8, to
be precise.

[Historical aside: I did, however, produce a version of Gofer at one
stage that didn't use dictionaries: the compiler still used a
dictionary passing translation internally, but then followed that
with a specialization phase so that no dictionary values were used
at run-time.  To my initial surprise, it actually resulted in smaller
compiled programs in every example that I tried.  Two caveats: (1) the
technique doesn't work well with separate compilation, and would need
a very fancy linker; (2) the introduction of polymorphic recursion in
Haskell means that there are programs for which the technique cannot
be used.  You can read more about this in my paper on "Dictionary-free
overloading".]

| - Does this work completely as intended or have I missed something, such
|   as strictness problems or the like?

Well I hope I've dealt with all this above.  One thing to note,
however: when you add extra arguments to a variable definition, you
can end up with a function where there wasn't one before, and that
has an impact on which computations get shared, and which don't.
So it can have an impact, and that was one of the original motivations
for the "dreaded monomorphism restriction", which is still there
lurking in the definition of Haskell 98.

| - Does this still work if more complex features of the type/class system
|   are used?

Yes to all the things you listed.  (Except your last point --- "dependent
types" --- to which I'd reply that I'm not exactly sure what you were
referring to ... perhaps the kind of work that Hongwei Xi has been
doing?  Or maybe to the kinds of things that you've seen in Lennart's
Cayenne?  Or perhaps something else.)

| - Can the transformed program be evaluated as efficiently as the
|   original one? (The original program gets an advantage if some class
|   constraints are resolved at compile time. But perhaps a similar effect
|   for the transformed program can be achieved with GHC's transformation
|   rules.)

The real question here is how can the program be executed at all
*without* doing the translation.  This is one of the criticisms
that has been made of Haskell's class mechanisms, and one of the
motivations for other proposals.  You might, for example, want to
take a first look at Odersky, Wadler, and Wehr's "A second look
at overloading" to see the kind of compromises that you might need
to make and the benefits that you might hope to gain.

| - Do type classes provide an advantage with respect to expressiveness of
|   types? For example, can the types of an API be formulated in a more
|   flexible way with classes as compared to the transformed style?

They shouldn't, in theory, but along the route to Haskell, some
additional expressiveness snuck in.  Dictionary components in
Haskell, for example, can have polymorphic types (think of fmap
in the Functor class), but the components of a tuple in a regular
Haskell type cannot.  Similarly, before Haskell went official and
allowed polymorphic recursion, you could still code it up by
hacking with classes.  You can restore the balance by adding
support for rank-2 polymorphism, as is done in Hugs and GHC.
Once that's don't you don't get an extra expressiveness by programming
with type classes, but it might still make some programs seem easier
to code (because you don't have to add the extra parameters yourself).

[Historical aside 2: when constructor classes were first introduced,
several people (myself included) wrote about the "Expressiveness
of constructor classes" ... it was only later that I realized how
much of that expressiveness came from rank-2 polymorphism instead
of higher-order kinds.  I wrote something about this in the tail
sections of my paper on "First-class polymorphism with type inference"
if you want to know more.]

| Most of this is probably well-known 

Re: Implementation of type classes

1999-09-11 Thread Jan Skibinski



On Sat, 11 Sep 1999, Heribert Schuetz wrote:

 
 Most of this is probably well-known stuff and written down in papers.
 Which ones? The Haskell report concentrates on the static semantics of
 classes and instances. It looks like the dynamic semantics is expected
 to be already understood by the reader or intuitively clear. Are the
 references [6] (Jones: A system of constructor classes: overloading and
 implicit higher-order polymorphism) and [11] (Wadler/Blott: How to make
 ad hoc polymorphism less ad hoc) of the report available on the Web?
 

Have you read "Typing Haskell in Haskell" by Mark P.
Jones? 
(written not so long ago, available on Web and to be presented
in Haskell Workshop 1999).
It  might help you with some of your questions.

Jan