Haskell' - class aliases

John Meacham john at repetae.net
Fri May 2 06:21:23 EDT 2008


On Fri, May 02, 2008 at 10:00:32AM +0100, Simon Peyton-Jones wrote:
> John
>
> This is good stuff, but I fear that in 3 months time it'll be buried
> in our email archives. In contrast, your original web page is alive
> and well, and we were able to start our discussion based on it
>
> So can I suggest that you transfer your web page to the Haskell' wiki
> (simply a convenient, editable place to develop it), or to the
> haskell.org wiki (likewise).  And that, as the design gets fleshed
> out, you try to reflect the current state of play there? I don't want
> this work to be lost!

Yes. I will try to do that. if anyone else wants to go ahead and do it,
that would be fine too.

> Ok, on to your email:
>
> =============== Desugaring the class alias decl ================= |
> there are two different desugaring rules, one for instances, one for
> the | alias appearing anywhere other than an instance declaration: | |
> > g :: A a => a -> b | > g = ...  | | translates to | | > g :: (S a,
> > C1 a, C2 a) => a -> b | > g = ...  | | the triplet of (S a, C1 a, C2
> > a) is completely equivalent to (A a) in | all ways and all places
> > (other than instance heads)
>
> Notice that this part *is* exactly true of a superclass with no
> methods
>
>         class (S a, C1 a, C2 a) => A a where {}

No, this isn't true. imagine

> f :: (S a, C1 a, C2 a) => a -> Int
> f x = g x

> g :: A a => a -> Int
> g x = ....

If A is a class alias, then this compiles just fine, if A is a
concrete class with superclasses, then it doesn't necessarily.

> That's not necessarily bad; but it does make it harder to figure out
> when to user a superclass and when to use a class alias.  Does that
> make sense?
>
> In fact, I suggest the following (**): the class alias
>
> > class alias S a => A a = (C1 a, C2 a) where f1 = nd1
>
> desugars to
>
>   class (S a, C1 a, C2 a) => A a
>
> The class alias decl *also* affects the desugaring of instances, still
> to come, but by desugaring the class alias into an ordinary class, you
> don't have to say *anything* about g :: (S a, C1 a, C2 a) => a -> b vs
> g :: (A a) => a -> b



But there is a difference, as noted above. And how can you decide
whether the expansion:

> class S a
> class S a => A a
> instance A Int

is supposed to declare an instance for 'S Int' as well as 'A Int' or
produce an error? Neither is a good choice universally. which is why I
made the distinction explicit in my class alias proposal.

> =============== Desugaring instanc decls =================
> | now for instance declarations
> |
> | > instance A a where
> | >         f2 = bf2
> |
> | expands to
> |
> | > instance (S a) => C1 a where
> | >         f1 = nd1
> |
> | > instance (S a) => C2 a where
> | >         f2 = bf2
> | >         f3 = d3
>
> Do you really mean that? Presumably 'a' is not a type variable here?
> Furthermore, instance decls typically have a context.  Unless I have
> profoundly misunderstood, I think you mean this:

Yeah, a is likely not a type variable, so it will be of form 'S Foo' for
some concrete type 'Foo'. Which is checked at compile time (just as if a
method of S were used in a default) and produce an error if such an
instance doesn't exist.

>   instance (Foo a, Bar b) => A (a,b) where f1 = bf1
>
> expands to
>
>   instance (Foo a, Bar b) => C1 (a,b) where f1 = nd1
>
>   instance (Foo a, Bar b) => C2 (a,b) where f2 = bf2 f2 = d3
>
> Notice the *absence* of an instance for (S (a,b)).  It's up to the
> *user* to ensure that there is such an instance, perhaps, say
>
>         instance Foo a => S (a,b) where ...

No, the 'S a' as appended to whatever instance context you provide. so

>   instance (Foo a, Bar b) => A (a,b) where f1 = bf1

expands to

>   instance (S (a,b), Foo a, Bar b) => C1 (a,b) where f1 = nd1
>   instance (S (a,b), Foo a, Bar b) => C2 (a,b) where f2 = bf2 f2 = d3

If 'S (a,b)' is not entailed by the environment in scope then the
declaration produces an error.

> In this way S is behaving just like any ordinary superclass.  If we
> have
>
>         class S a => T a then given an instance instance (Foo a, Bar
>         b) => T (a,b) it's up to the user to ensure that there is an
>         instance for S (a,b).
>
>
> With the desugaring (**) I proposed above, we'd add one more instance:
> instance (Foo a, Bar b) => A (a,b)

Yes, but we explicitly did not want to add that instance by using a
class alias context rather than putting it in the expansion, for a
similar reason we don't create a dummy 'Eq' instance when someone
declares something an instance of 'Num' even though Eq is a superclass
of Num.  The 'class alias context' vs 'class alias expansion' is there
to make that distinction clear and unambigous, the expansion is what you
declare with an instance, the context is a prerequisite for creating an
instance.

        John

-- 
John Meacham - ⑆repetae.net⑆john⑈


More information about the Haskell-prime mailing list