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

Reply via email to