Bulat Ziganshin <[EMAIL PROTECTED]> writes: > > Yes - you've reiterated Wadler's original design, with > > an automatic problems with equational reasoning raised > > by this approach. > > ok, i can live without it. i mean reasoning :)
That's probably not good, but I don't follow that problem yet. I'm afraid I've not had the stamina to follow this thread properly, and I doubt if I'll get any more stamina soon, so let me make a proposal not too disimilar to Bulat's and just hope that people find it appealing enough to flesh it out. The idea I'm presenting is simple enough: allow data constructors as members of classes. (Sure, David, this does have the problem of hiding potentially expensive operations as straightforward pattern matches, but that's abstraction for you). So class Sequence s where (some other stuff) Cons:: a -> s a -> s a Nil:: s a Here Cons and Nil both stand for two things: a constructor and a deconstructor. The question is how to specify the values of the two parts when giving an instance. The easiest way is just to give it in terms of something that already has the two aspects: instance Sequence [] where ... Cons = (::) Nil = [] And so a definition like f Nil = ... f (Cons a l) = ... gets a type like Sequence s => s a -> ... But we also want it to work for cases where the type we are viewing doesn't already have a constructor that does what we want, such as giving a list instance for another member of Sequence: class Sequence s where Snoc:: s a -> a -> s a (some other stuff) The idea here would be to announce that all data constructors really do have two parts and they are accessed via qualified names. So the Snoc part of the list instance would look like this: ... Snoc.construct l x = l ++ [x] Snoc.deconstruct f g [] = g Snoc.deconstruct f g l = f (init l) (last l) (We can of course argue about the precise type used for deconstructors and there is endless bikeshed painting to be done for the names construct and deconstruct, but I hope this gives the general idea). I think this proposal is simpler than the earlier ones presented -- enough that someone in better shape than me could work out the details and implement it. There's no exciting new syntax, just an extension of some current syntax to a new area, and functions declared using a "view" are automatically overloaded for everything that shares the view. As far as equational reasoning goes, I think the approach would be to specify what laws Foo.construct and Foo.deconstruct have to follow to preserve it, and leave them up to the programmer to respect (in the same way that the monad laws aren't tested by the compiler). -- Jón Fairbairn [EMAIL PROTECTED] _______________________________________________ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime