Generic deriving: new default methods
José Pedro Magalhães
jpm at cs.uu.nl
Thu Jan 13 10:31:02 CET 2011
Ok, so I think we reached a possible solution here. Summarizing: for a class
C
class (Ctx1) => C a where
> noDef :: a
>
> h98Def :: a
> h98Def = ...
>
> genDef :: a
> generic genDef :: (Ctx2) => a
> genDef = ...
>
instances are defined like this:
instance C T where
> noDef = ... -- we need to write this!
> h98Def = ... -- if we don't write this line, the H98 default is used
> genDef = ... -- if we don't write this line, the generic default is used
>
So, for the purposes of the new generic deriving mechanism, "deriving"
clauses attached to a datatype or standalone deriving will not be affected.
Generic instances are derived using instance declarations which do not
define methods with generic defaults.
Going back to the discussion of having both H98 and generic defaults, I
think it's a bit of a pity that we lose that possibility. The original idea
of our work was to be able to specify in Haskell the behavior of the
deriving mechanism for the standard classes. Take the Eq class as an
example:
class Eq a where
> (==), (/=) :: a -> a -> Bool
>
> a == b = not (a /= b)
> a /= b = not (a == b)
>
If we were to change the Eq class to accurately refer that it is derivable,
we would need to make one of the two methods generic. Let's say we make (==)
generic. Then we'd have:
class Eq a where
> (==) , (/=) :: a -> a -> Bool
>
> a /= b = not (a == b)
>
> generic (==) :: (...) => a -> a -> Bool
> (==) = genericEqDefault
>
So we lose the H98 default for (==). Unfortunately this can be problematic,
because if a user defines an instance of Eq by defining (/=) alone, s/he
will get the generic implementation for (==), which s/he might not want. A
workaround for the user is to also define (==) explicitly as the negation of
(/=).
A minor thing, perhaps, but I mention it for the record. If there is no more
discussion I think we can proceed with the implementation.
Thanks,
Pedro
2011/1/12 Simon Peyton-Jones <simonpj at microsoft.com>
> If everyone finds this acceptable, I will proceed to implement it in
> this way. In summary:
> - Generic defaults are marked by the (new) keyword "generic"
> - Generic defaults have a type which has to be the same as the class method
> they refer to. The context, however, can differ.
> - A method can have at most one default declaration, be it H98-style or the
> new generic default.
> - A class can have any number of methods with (H98 or generic) defaults.
>
> YES
>
> One thing remains: how do we actually specify the derived instance? I think
> there are two options. For the class D above, we can do
>
> deriving instance C T
>
> or
>
> instance D T
>
>
> The second option is justified by dop having a default; generic defaults
> would work like H98 defaults do in this matter. *LET’S DO THE SECOND,
> just like H98!!
> *
>
> However, consider a more general case:
>
> class C a where
> noDef :: a
>
> h98Def :: a
> h98Def = ...
>
> genDef :: a
> generic genDef :: (Representable a) => a
> genDef = ...
>
>
> Now, how do we derive instances of C for the user-defined datatype T? We
> need to provide a definition for noDef, so we can only do something like
>
> instance C T where
> noDef = ... -- we need to write this!
> h98Def = ... -- if we don't write this line, the H98 default is used
> genDef = ... -- if we don't write this line, the generic default is used
>
>
>
> There’s no problem here. In H98 you can write
>
> instance C T where {}
>
> and the compiler will fill in the polymorphic default methods with what you
> specify. If you don’t specify one (like noDef above), then it’s just as if
> you’d said
>
> class C a where
>
> noDef :: a
>
> noDef = error “No default method specified for noDef”
>
>
>
> (Actually GHC warns you at the instance decl; and fills in better one like
> this:
>
>
>
> instance C T where
>
> noDef = error “No default method specified in instance (C T)
> on line xxx”
>
> )
>
>
>
> So when you derive instances for C, you simply say
>
>
>
> instance C T
>
>
>
> just as you do now. The fact that it’s a **generic** default is driven by
> the way the class decl specifies the default.
>
>
>
> Does that make sense? Of course we’d better document this carefullly.
>
>
>
> Simon
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/cvs-ghc/attachments/20110113/be29ffbc/attachment.htm>
More information about the Cvs-ghc
mailing list