Several thoughts First, about type families: deriving instance (Representable0 a rep, GenericEq rep) => Eq a where eq = genericEqDefault
Didn't we decide to use type families, in the end ? So this would be deriving instance (Representable0 a, GenericEq (Rep a)) => Eq a where eq = genericEqDefault where Rep is the type family? Returning to your main qn. In our Derivable Type Classes work each method of a class could have 1. No default method, OR 2. A polymorphic default method (a la Haskell 98), OR 3. A generic default method (a la Derivable Type Classes) e.g. class C a where op1 :: a -> a op2 :: a -> a op2 x = x op3 :: a -> a op3 {| p + a |} (Left x) = ... ... etc... The methods op1, op2, op3 illustrate the three cases. Note that (a) the choice is made once for all in the class decl, and (b) it can be made independently for each method. This decision, made in the class decl, specifies what to do when you have an instance declaration instance ... => C (T a) where ...no method specified for 'op'... If no method is specified in the instance, it is "filled in" in the way specified in the class decl. In the three cases: 1. No default => fill in with "error "missing method op1"" 2. Polymorphic default => fill in with a call to the default function 3. DTC generic default => generate code according to the template I think we should just do the same. Add a fourth choice (well, the third might disappear!) Something like class C a where op4 :: [a] -> a deriving op4 = genericOp4Default -- Syntax? Then, in an instance decl, if op4 is specified with a Pedro-deriving spec as above in the class decl, and the instance decl gives no defn for op4, then we fill in with the specified code. Thoughts: · The definition for op4 in the class decl should have form Cxt => [a] -> a, but there's no inherent reason that Cxt must be (Representable ... ). I suppose we could simply infer it. Then we could say, for example, class C a where op4 :: [a] -> a deriving op4 = minimum :: Ord a => [a] -> a instance Ord a => C (T a) The instance would behave exactly as if you'd written instance Ord a => C (T a) where op4 = minimum which would be fine if (T a) was an instance of Ord. · I'm not sure about the syntax for specifying that op4 is a generic-deriving method. A pragma is not good, because the program is meant to make sense without them. · Suppose that you wanted *all* the methods of an instance to use the generic deriving mechanism. Then you could write instance Cxt => C (T a) and all is fine. The *instance* doesn't have to say "deriving" stuff. But if C had generic-deriving methods, then Cxt might well need to include (Representable0 a) etc. Simon From: José Pedro Magalhães [mailto:j...@cs.uu.nl] Sent: 06 January 2011 15:55 To: Simon Peyton-Jones Cc: atze; Johan Jeuring; Andres Löh; cvs-ghc@haskell.org Subject: Generic deriving: new default methods Hello Simon and all, I am not sure what is the best way to proceed with the generic default methods. But first, some context: for the new generic deriving mechanism, being implemented in GHC [1] in a way similar to UHC [2], we need some form of default generic methods. Taking the Eq class and (==) as example: class Eq a where -- type signatures eq, neq :: a -> a -> Bool -- regular defaults eq a b = not (neq a b) neq a b = not (eq a b) Our generic eq uses a class class GenericEq f where geq :: f a -> f a -> Bool and a default method, which takes care of conversion from a user-defined datatype to its representation, and then applying the generic function [3]: genericEqDefault :: (Representable0 a rep, GenericEq rep) => a -> a -> Bool genericEqDefault a b = geq (from0 a) (from0 b) To be able to derive generic equality for a user-defined datatype D, we need to generate an instance Eq D where eq is genericEqDefault. That is: instance Eq D where eq = genericEqDefault So the compiler has to know that this genericEqDefault is somehow associated to the Eq class. In UHC we used a pragma: {-# DERIVABLE Eq eq genericEqDefault #-} That is, class Eq has a generic method eq with default implementation genericEqDefault. For GHC, we first thought of something like: class Eq a where ... -- all the stuff as before deriving eq = genericEqDefault That is, the generic default would stay together with the class declaration, a bit like regular defaults [4]. The problem here is that the "deriving eq" part doesn't really typecheck under the same context as the regular default: we need the context (Representable0 a rep, GenericEq rep). What is the best choice here? We could decide to accept the code above and implicitly use the context from genericEqDefault. I'm not sure on what kind of error messages this would result, though. Another alternative is to decouple the generic default, as in UHC. Proper syntax for the DERIVABLE pragma could be something like: deriving instance (Representable0 a rep, GenericEq rep) => Eq a where eq = genericEqDefault I'm happy to hear your thoughts on this. Cheers, Pedro [1] http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/GenericDeriving [2] http://www.dreixel.net/research/pdf/gdmh_nocolor.pdf [3] In UHC we needed to pass the representation explicitly as an argument to genericEqDefault. In GHC, if we use FunctionalDependencies or TypeFamilies, we can avoid this. [4] Note that we must keep regular defaults as well, since users might want to use the Eq class without any generics.
_______________________________________________ Cvs-ghc mailing list Cvs-ghc@haskell.org http://www.haskell.org/mailman/listinfo/cvs-ghc