
On Thu, May 01, 2008 at 11:57:14PM +0100, Simon Peyton-Jones wrote:
| > Fair enough. But the strange syntax | > | > class alias Num a = Eq a => (Additive a, Multiplicative a) | > | > *does* seem so say that the (Eq a) behaves in a superclass way, and | > (Additive a, Multiplicative a) behave in a class-alias way, as it | > were. That seems inconsistent with the design goal you describe | > above. | | Wolfgang suggested the alternate syntax | | class alias Eq a => Num a = (Additive a, Multiplicative a) where .... | | The correct reading being: | | if 'Eq a' then 'Num a' is an alias for (Additive a,Multiplicative a) | | I think I am coming around to his point of view, do you think this makes | it clearer?
I am not arguing about syntax!
oh, I just meant that this syntax is actually a different way of thinking about it for me and it helped me clarify some stuff in my mind so thought it might be clearer for others as well.
You say "class aliases are orthogonal to superclasses", but then you allow this "Eq a" thing in the above alias, which is very like a superclass. I think that if you allow the "Eq a =>" part, you should also allow new methods to be declared in the alias (as I originally thought you did). And if not, then you shouldn't allow superclasses. It's precisely that you allow superclasses (Eq a =>) that makes your feature non-orthogonal to ordinary superclasses. Maybe you can't make them orthogonal, but it quite hard to explain this definition to me.
Oh, the reason to allow superclasses of class aliases is so methods of the superclass can be used in the default instance methods for your alias. In addition, it allows full emulation of any explicit class you can currently declare. You do not want 'instance 'Num a'' to declare an instance for Eq as that is very different behavior from the old Num class. Yet the default instances for 'Num' may require use of methods from its superclass. it actually would make more sense to call them the context of the class alias rather than the superclass, since they don't declare a super/sub class relationship between the two.
Incidentally, you say that your proposal is just syntactic sugar: if so, can you give the desugaring translation?
Hmm.. okay, here is a rough draft that covers all the important cases I think. assume the following declarations:
class C1 a where f1 :: t1 f1 = d1
class C2 a where f2 :: t2 f2 = d2 f3 :: t3 f3 = d3
class alias S a => A a = (C1 a, C2 a) where f1 = nd1
okay, the desugaring is as follows: 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), one is just a different way to express the other, just like type synonyms. An alias just expands to the union of the classes it is an alias for as well as its class constraints (superclasses). 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
Note that when declaring an instance of a concrete type, like Int, the constraint (S Int) will be trivially satisfied or not at compile time. (bf2 is free to use methods of 'S' of course). this translation is also a bijection, declaring those two instances manually as above is indistinguishable from declaring instances via the alias in all ways. Hopefully the generalization to arbitrary numbers of classes is clear... John -- John Meacham - ⑆repetae.net⑆john⑈