Re: Haskell' - class aliases
| which leads me to a problem i have with ATs, which applies | to class aliases as well: although the ATs are written as if they | were local to the class, they get lifted out of the class in a naive | manner. in particular, they can only refer to their parameters, | not to other local definitions/types, and their parameters have | to match the class parameters. I'm not sure what you mean here, Claus. Can you give a concrete example? sure. here's one from practice, even. there was a thread on haskell-cafe on how to re-export FD-based libraries in AT-based form (for better match with AT-based client code). the obvious translation of class FD a b | a - b would seem to be class AT a where type AT a but, as it turns out, you can't write instance FD a b = AT a where type AT a = b because the 'b' is not in scope! from an AT-based perspective, it ought to be in scope, because the AT definition is local to the instance, but the AT seems to be implemented as sugar for a non-local TF, for which the local 'b' is not available (i'm not sure why there is no lambda-lifting behind the scenes to add that 'b' parameter, in a hidden form?). the thread, and Manuel's explanation, are here: http://www.haskell.org/pipermail/haskell-cafe/2008-March/041168.html this is likely to be less of a problem for class aliases, because the component class instances share not only the same form of instance head, but also the same context (so if a type is functionally determined by the context in one component, it is so in all components). btw, if type family instances could have contexts that functionally determine extra type parameters, the original poster wouldn't have to duplicate his FDs as TFs, as suggested in that email, but could simply write (i think?-): type instance AT a = FD a b = b claus ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
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... What about multiple parameters? Can A have more parameters than the Ci? Should they be in the same order? Should they overlap? What about instance contexts, like: instance I a = A a where ... (What about functional dependencies?) Tom -- Tom Schrijvers Department of Computer Science K.U. Leuven Celestijnenlaan 200A B-3001 Heverlee Belgium tel: +32 16 327544 e-mail: [EMAIL PROTECTED] url: http://www.cs.kuleuven.be/~toms/ ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
Any chance to express this in terms of a formal (constraint rewrite framework). For example, the Haskell rule, do *not* display implied superclasses, can be specified as follows. Consider the special case of class Eq a class Eq a = Ord a Eq a, Ord a = Ord a The above rule only applies *after* type inference took place. Martin John Meacham wrote: This isn't really a response to your email, but I have been mulling the last few hours away from a computer and wanted to get this stream of conciousness out when it is fresh in my mind. The more I think about it, I think 'superclass' is just the wrong terminology for dealing with class aliases. Superclass implies a strict partial order on classes, which just isn't the case for class aliases, for instance class alias Foo a = Foo a = Bar a where ... Has a defined (if not very useful) meaning with class aliases, but is really odd if you consider 'Foo a' a superclass. So, I think the following terminology should be used: Context of --+ alias| The alias -++--- The expansion of the alias ||| vvv class alias (S1 a .. Sn a) = A a = (C1 a ... Cn a) where fd1 = fdn = ^ + The defaults of the alias given this, the expansion of 'A a' in any context other than an instance head is A a -- reduce(S1 a .. Sn a, C1 a ... Cn a) where reduce is standard entailment reduction on class contexts (like (Eq a,Ord a, Eq a) reduces to (Ord a)) This expansion is carried out iteratively on all class aliases until a fixed point is reached, then all class aliases are deleted from the result and the remaining context is the final result. (This will always terminate due to there being a finite number of class aliases that can be pulled into the expansion) likewise, for instance declarations: instance A a where ... -- foreach C in C1 .. Cn: instance (S1 a ... Sn a) = C a where ... I left out the default methods here. I need to think about them a bit more to come up with a formal expansion as it is a bit trickier (to typeset if nothing else), but I hope this is somewhat more clear for some... John ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
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⑈ ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
RE: Haskell' - class aliases
| The more I think about it, I think 'superclass' is just the wrong | terminology for dealing with class aliases. Superclass implies a strict | partial order on classes, which just isn't the case for class aliases, | for instance | | class alias Foo a = Foo a = Bar a where ... Crumbs! I have no idea what that means! Did you really mean to repeat Foo? According to your expansion in type signatures f :: (Foo a) = ... expands to f :: (Foo a, Bar a) = ... which presumably expands again. I'm totally lost here Have a look at my last message, which gives a variant of your desugaring that IMHO greatly clarifies the meaning of (what I understand by) aliases. Simon ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
RE: Haskell' - class aliases
| Crumbs! I have no idea what that means! Did you really mean to repeat Foo? According to your | expansion in type signatures | f :: (Foo a) = ... | expands to | f :: (Foo a, Bar a) = ... | which presumably expands again. I'm totally lost here | | Yes I did, because I wanted to make the differences between class alias | contexts and superclasses very clear, the above context is valid, if | vacuous. the expansion goes as follows . | 1. Foo a -- reduce(Foo a,Bar a) | -- Foo a expanded ... Even more crumbs! Is this fixpoint iteration (being careful to avoid infinite expansion) *really* essential to your proposal? That would be a significant and unwelcome thing IMHO. To be concrete, consider f :: (Foo a) = ... In GHC, f really takes an extra dictionary argument for the class Foo. If aliases mean aliases in the sense of type synonyms (which I think you intend) you must expand Foo to find out whether f takes zero, one, or many dictionary arguments. Furthermore, everyone must expand in precisely the same way, so that we agree on the order of these arguments. That's reasonably simple if expand simply means normalise; but it's more complicated if there's a fixpoint algorithm involved. So is this really crucial? Simon ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
On Fri, May 02, 2008 at 11:24:11AM +0100, Simon Peyton-Jones wrote: | The more I think about it, I think 'superclass' is just the wrong | terminology for dealing with class aliases. Superclass implies a strict | partial order on classes, which just isn't the case for class aliases, | for instance | | class alias Foo a = Foo a = Bar a where ... Crumbs! I have no idea what that means! Did you really mean to repeat Foo? According to your expansion in type signatures f :: (Foo a) = ... expands to f :: (Foo a, Bar a) = ... which presumably expands again. I'm totally lost here Yes I did, because I wanted to make the differences between class alias contexts and superclasses very clear, the above context is valid, if vacuous. the expansion goes as follows . 1. Foo a -- reduce(Foo a,Bar a) -- Foo a expanded 2. reduce(Foo a,Bar a) -- (Foo a,Bar a) -- no entailment reduction possible, reduction is unchanged from H98 3. (Foo a,Bar a) - reduce(Foo a,Bar a,Bar a) -- Foo a expanded 4. reduce(Foo a, Bar a, Bar a) - (Foo a, Bar a) -- reductino removes duplicates 5. we notice we are the same as in step #2. fixed point reached, we stop expansion. 6. we remove all class aliases from result: (Foo a, Bar a) - Bar a 7. 'Bar a' is our final result. informal proof of termination: each step adds a new class or class alias to the context, there are a finite number of classes or class aliases, therefore we must eventually reach a fixed point. Have a look at my last message, which gives a variant of your desugaring that IMHO greatly clarifies the meaning of (what I understand by) aliases. I think the difference in what we mean is that I intend class aliases to be a true bijection in all contexts (isomorphism?) between a single alias and a set of classes. This is opposed to superclasses which are a one directional implication. One of my main motivations is being able to mix unchanged H98 and H' code (with different numerical hierarchies, and both calling each other) without modifications or prefered treatment for either. this means instances for H' must silently and transparently create instances for H98 classes and vice versa, moreso, type signatures should be compatible. As in, the H' specification should be able to make absolutely no reference to H98 and vice versa, yet class aliases allow one to write a compiler that seamlessly allows mixing code from the two without compromising the design of either. John -- John Meacham - ⑆repetae.net⑆john⑈ ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
On Fri, May 02, 2008 at 11:54:13AM +0100, Simon Peyton-Jones wrote: Even more crumbs! Is this fixpoint iteration (being careful to avoid infinite expansion) *really* essential to your proposal? That would be a significant and unwelcome thing IMHO. To be concrete, consider f :: (Foo a) = ... In GHC, f really takes an extra dictionary argument for the class Foo. If aliases mean aliases in the sense of type synonyms (which I think you intend) you must expand Foo to find out whether f takes zero, one, or many dictionary arguments. Furthermore, everyone must expand in precisely the same way, so that we agree on the order of these arguments. That's reasonably simple if expand simply means normalise; but it's more complicated if there's a fixpoint algorithm involved. Yeah, I do mean normalize I think. There is no run time representation of class aliases at all so this issue doesn't arise. f will just take a 'Bar' dictionary argument. I am envisioning class alias expansion taking place very early in the desugaring, certainly before any transformation to ghc core and turning contexts into dictionary arguments. So is this really crucial? Probably not, minimal fixpoint calculations are just what I find the simplest way to formally define/think about things. In this case, I am sure a simpler straight up normalization algorithm can be used to get equivalent results... but minimal fixpoints are so easy to implement in haskell and formally well defined that I am not sure of the value of specifying the extension in terms of it. It of course doesn't mean compilers have to perform the fixpoint iteration, it is just a declarative statement of what class aliases are equivalent to. John -- John Meacham - ⑆repetae.net⑆john⑈ ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
A aliasing of constraints/classes (this is the semantic part that could also be explained by reduction, or by simple mutual implication encodings) B aliasing of syntax, especially instance definitions (this syntactic part is hard to encode, and simple in terms of syntactic macro expansion) it just occurred to me that there is a precedence for this kind of translation, in associated types and type functions. defining an AT in a class is equivalent to defining a TF outside the class, and connecting the TF to the class with superclass and instance constraints, right? class C a where type CT a c :: (a,CT a) instance C a where type CT a = .. c = .. -- vs type family CT a type instance CT a = .. class CT a ~ b = C a where c :: (a,CT a) instance CT a ~ b = C a where c = .. though the latter form is not yet supported in GHC (#714). which leads me to a problem i have with ATs, which applies to class aliases as well: although the ATs are written as if they were local to the class, they get lifted out of the class in a naive manner. in particular, they can only refer to their parameters, not to other local definitions/types, and their parameters have to match the class parameters. however, i assume that the restrictions/translations/implementations for class aliases are similar to the those for the implementation of ATs in terms of TFs, which might help? claus ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
On Thu, May 01, 2008 at 03:42:53PM +0100, Simon Peyton-Jones wrote: | Yeah, I disagree here, mainly because I don't want to conflate | superclasses with class aliases. I feel they have different uses, even | though they can sometimes achieve the same thing. 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? John -- John Meacham - ⑆repetae.net⑆john⑈ ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
RE: Haskell' - class aliases
| 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! 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. Incidentally, you say that your proposal is just syntactic sugar: if so, can you give the desugaring translation? Simon ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
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⑈ ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
Is this the most up-to-date description of the proposal? http://repetae.net/recent/out/classalias.html what sounds nice about the class alias proposal is that it is pure sugar, at least to the extent that type aliases are, but the design principle behind it seems to be that there should be a separate class for each method (as in Clean?), and that any compound classes should really just be class aliases (made to look like compound classes by the sugar), so that rearranging compound classes comes down to defining more aliases for the same single-method base classes. since this looks like class equivalence plus namespace handling, i was wondering how far one could get without the proposed extension. this is slightly more difficult than the proposed translation (which splits compound aliases into their components, so that the alias class is always translated away), but it might still be of interest. consider the 'class alias FooBar a = (Foo a,Bar a)' example from the proposal page. we define FooBar and Foor/Bar in separate modules and use that for namespace management. - FooAndBar defines Foo and Bar, as well as a type X which is an instance of both - FooBar defines FooBar, implicit derivations of FooBar from Foo/Bar and vice-versa (the aliasing part), as well as a type Y which is an instance of FooBar FooBar also arranges for Y to be an instance of Foo/Bar, and for X to be an instance of FooBar, via the implicit derivations, but controlled by instances of How note the class 'How' and its instances, which ensure that any type class instance is either defined, or derived (in a unique, specified way), but never both. problems: (1) instance method definitions by qualified names are not permitted, leading to the confusing 'foo = foo' (cf separate thread) (2) overlapping instances, due to the derived instances; it seems this can be held in check by the use of 'How', at the expense of some extra parameters/contexts/ instances to control how each instance is defined/derived example session: *FooBar foo (X 1) False *FooBar bar 0 (X 1) [X 1] *FooBar foo (Y 1) True *FooBar bar 0 (Y 1) [Y 1,Y 1] *FooBar FooAndBar.foo (X 1) False *FooBar FooAndBar.foo (Y 1) True *FooBar FooAndBar.bar 0 (X 1) [X 1] *FooBar FooAndBar.bar 0 (Y 1) [Y 1,Y 1] *FooBar :t foo foo :: (FooBar a how) = a - Bool *FooBar :t FooAndBar.foo FooAndBar.foo :: (Foo a how) = a - Bool *FooBar :t bar bar :: (FooBar a how) = Int - a - [a] *FooBar :t FooAndBar.bar FooAndBar.bar :: (Bar b how) = Int - b - [b] i don't think i'd recommend this encoding style (it does not quite fullfill the criterion of simplicity!-), but there you are: class aliases encoded. hth, claus ps. (for the TF vs FD fans: replacing FD class 'How' with a TF doesn't seem to work; a bug?) FooAndBar.hs Description: Binary data FooBar.hs Description: Binary data ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
RE: Haskell' - class aliases
John OK here's a question about class alisas. You propose: class Foo a where foo :: a - [a] foo x = [] class Bar a where bar :: a - a bar x = [x] class alias FooBar a = (Foo a, Bar a) where foobar :: a - a foobar x = x foo x = bar x I have a few minor questions about this that'd be worth clarifying on your main page (a) I assume you can add a method 'foobar' not declared in either Foo or Bar. Your very first example has this. But it's contradicted later when you say that One can declare an instance of Num either by giving separate instances for Eq, Additive, Multiplicative (b) And I assume that you don't need to repeat the type signatures for 'foo' and 'bar'. (c) I think you intend that you can override the default methods for foo and bar; and I have done so for method 'foo'. Question: how does the above differ from this? class (Foo a, Bar a) = FooBarSC a where foobar :: a - a Here Foo, Bar are simply superclasses. From the point of view of a type signature there *no* difference: f :: (FooBarSC a) = ... gives access to all the methods of Foo and Bar. So what's the difference? Answer (I believe): when you give an instance of FooBar you give implementations for all methods of Foo, Bar, and FooBar. So the obvious question is: do we really need a new construct? Why not just use FooBarSC? Then we'd have to allow you to give implementations for superclass methods too: instance FooBarSC Int where foobar = ... foo = ... bar = ... I think I believe (like you) that this is a bad idea. The main reason is that it's a totally unclear whether, given a FooBarSC Int instance declaration, should there be an instance for (Foo Int), always, never, or optionally? However, I think you might want to articulate the reasons carefully, because we have two features that are really extremely close. To put it another way, you could imagine re-expressing your proposal like this: class (Eq a) (Additive a, Multiplicative a) = Num a meaning this: when you give an instance for (FooBar T) you * MUST give implementations for the methods of Addititive and Applicative * MUST NOT give implementations for methods of Eq; rather the Eq T instance must be in scope. This is, I believe, what you mean by class alias Num a = Eq a = (Additive a, Multiplicative a) Now I'm not necessarily suggesting this as concrete syntax. But my point is that you're really asking for small modification of the existing superclass mechanism, that divides the superclasses into two groups, the flat ones (like Additive and Multiplicative) and the nested ones (like Eq). Is that right? If so, a syntax that is more suggestive of the current superclass declaration looks better to me. This close relationship also suggests strongly that the answer to (a) above should be 'yes', since you can certainly add methods to a class with superclasses. I won't say more until I'm sure I've understood your intent. Simon ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
Simon Peyton-Jones wrote: Is this the most up-to-date description of the proposal? http://repetae.net/recent/out/classalias.html Has anyone looked at my (confusingly named and horribly written) variant? http://haskell.org/haskellwiki/Superclass_defaults My idea is to split class aliases into two separate things: 1. Superclass defaults: allow a class declaration to contain defaults for methods from superclasses. Allow an instance declaration to be for multiple classes at once, using the most specific defaults: instance (FooBar a, Foo a, Bar a) -- pick the defaults from FooBar, since it is a subclass -- of both Foo and Bar. 2. Class aliases: simply an alias for zero or more classes. class alias FooAndBar a = (Foo a, Bar a) In a context FooAndBar a is simply replaced by (Foo a, Bar a). For instantiation purposes the class alias could override the default methods as if it was a subclass of Foo and Bar. No new methods can be added. Alternatively class aliases could be just macros, like type synonyms. Part 1 applies for instance to the Functor/Applicative/Monad hierarchy, fmap could have a default in terms of (=). Part 2 is useful for splitting classes up into smaller bits. Twan ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
On Thu, Apr 24, 2008 at 10:21:03PM +0200, Wolfgang Jeltsch wrote: Am Donnerstag, 24. April 2008 21:27 schrieb John Meacham: On Thu, Apr 24, 2008 at 08:48:15PM +0200, Wolfgang Jeltsch wrote: […] I also have some remark: Why not write class Eq a = Num a = (Additive a, Multiplicative a) instead of class Num a = Eq a = (Additive a, Multiplicative a) Well, because you can think of 'Num a' as an alias for 'Eq a = (Additive a, Multiplicative a)', not that Eq is a superclass of Num which the class declaration syntax implies. Hmm, in what way is Num a an alias for Eq a = (Additive a, Multiplicative a)? You cannot write this: square :: (Eq a = (Additive a, Multiplicative a)) = a - a I would say: “Under the condition that Eq a holds, Num a is an alias for (Additive a, Multiplicative a). And this seems to be perfectly expressed by my above proposal. Hmm... I guess it depends on how you think about it. I tend to think about them in terms of what they are rewritten to rather than a proposition about classes. but perhaps that makes more sense. Will mull on it some.. John -- John Meacham - ⑆repetae.net⑆john⑈ ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
Am Mittwoch, 23. April 2008 06:18 schrieb John Meacham: On Tue, Apr 22, 2008 at 08:33:53AM +0100, Simon Peyton-Jones wrote: Is this the most up-to-date description of the proposal? http://repetae.net/recent/out/classalias.html There were a few changes proposed in the discussion that followed my announcement that I wanted to make. The one I can remember now is getting rid of the 'alias' keyword since the equals sign unabiguously identifies it as an alias. I will dig through the archive to find the others.. I've just had another look, which threw up quite a few questions in my mind. I wonder what would be a good list to discuss it. Maybe this one is not bad, because it has people interested in Haskell innovation, regardless of whether it's a live Haskell' candidate? Sounds good to me. John By the way, what are your current thoughts about your supertyping proposal. At least, on http://repetae.net/recent/out/supertyping.html you say: This functionality becomes even more necessary when faced with binary-only libraries and standard language features which cannot be easily rewritten or overridden without great effort. This seems to be an advantage compared to the class alias library. On the other hand, it looks a bit weird to me that you can express a class relation in two different ways: A t = B t and B t = A t. Best wishes, Wolfgang ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
RE: Haskell' - class aliases
| I tried to see the discussion that led to class aliases being rejected | as a proposal, but could not find links on the Wiki. In fact, in Trac | (#101) that proposal is still a 'maybe', but with no updates. Is there | a competing proposal that got accepted? | | [Without a mechanism like class aliases, breaking up Num into a | hierarchy of proper mathematical concepts becomes too unwieldly to be | realistic. This is a real stumbling block for anyone trying to use the | class system to encode fine-grained mathematical concepts.] I think this is partly my fault for failing to implement the idea -- a full implementation is really a prerequisite for Haskell'. One reason I've failed to do so is because I have not come under enough pressure! If I thought there were dozens of people slavering at the chops for class aliases, that would put it more firmly on my radar. Ben is right to say that it's much easier than the type-function stuff, which is decidedly tricky. (Of course there nothing stopping someone else doing it, but GHC's typechecker is one of it's more richly-interconnected parts.) Perhaps you have all just been very polite, and waiting in quiet but unrequited hope. Is this the most up-to-date description of the proposal? http://repetae.net/recent/out/classalias.html I've just had another look, which threw up quite a few questions in my mind. I wonder what would be a good list to discuss it. Maybe this one is not bad, because it has people interested in Haskell innovation, regardless of whether it's a live Haskell' candidate? Simon ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
On Tue, Apr 22, 2008 at 08:33:53AM +0100, Simon Peyton-Jones wrote: Is this the most up-to-date description of the proposal? http://repetae.net/recent/out/classalias.html There were a few changes proposed in the discussion that followed my announcement that I wanted to make. The one I can remember now is getting rid of the 'alias' keyword since the equals sign unabiguously identifies it as an alias. I will dig through the archive to find the others.. I've just had another look, which threw up quite a few questions in my mind. I wonder what would be a good list to discuss it. Maybe this one is not bad, because it has people interested in Haskell innovation, regardless of whether it's a live Haskell' candidate? Sounds good to me. John -- John Meacham - ⑆repetae.net⑆john⑈ ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Haskell' - class aliases
I tried to see the discussion that led to class aliases being rejected as a proposal, but could not find links on the Wiki. In fact, in Trac (#101) that proposal is still a 'maybe', but with no updates. Is there a competing proposal that got accepted? [Without a mechanism like class aliases, breaking up Num into a hierarchy of proper mathematical concepts becomes too unwieldly to be realistic. This is a real stumbling block for anyone trying to use the class system to encode fine-grained mathematical concepts.] Jacques ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
Re: Haskell' - class aliases
Jacques Carette wrote: I tried to see the discussion that led to class aliases being rejected as a proposal, but could not find links on the Wiki. In fact, in Trac (#101) that proposal is still a 'maybe', but with no updates. Is there a competing proposal that got accepted? [Without a mechanism like class aliases, breaking up Num into a hierarchy of proper mathematical concepts becomes too unwieldly to be realistic. This is a real stumbling block for anyone trying to use the class system to encode fine-grained mathematical concepts.] We want to get Haskell' done, and unfortunately that may mean rejecting some good proposals - in this case, class aliases is a fairly large feature that we don't have enough experience with yet, so it was dropped (I proposed dropping it recently to the committee, and no-one argued against). That's not to say it isn't worthwhile, and this certainly doesn't prevent it from being adopted in a future version of the standard. We'd like to see it implemented in GHC, too. BTW, by the end of this process I do want to make sure we've documented the rationale for all the decisions, so that future committees have a useful knowledge base to work from. Cheers, Simon ___ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime