| Copyright | (C) 2015-2016 Ryan Scott |
|---|---|
| License | BSD-style (see the file LICENSE) |
| Maintainer | Ryan Scott |
| Portability | Template Haskell |
| Safe Haskell | None |
| Language | Haskell2010 |
Data.Deriving
Contents
Description
This module reexports all of the functionality of the other modules in this library.
It also provides a high-level tutorial on deriving-compat's naming conventions and
best practices. Typeclass-specific information can be found in their respective
modules.
derive- functions
Functions with the derive- prefix can be used to automatically generate an instance
of a typeclass for a given datatype Name. Some examples:
{-# LANGUAGE TemplateHaskell #-}
import Data.Deriving
data Pair a = Pair a a
$(deriveFunctor ''Pair) -- instance Functor Pair where ...
data Product f g a = Product (f a) (g a)
$(deriveFoldable ''Product)
-- instance (Foldable f, Foldable g) => Foldable (Pair f g) where ...
If you are using template-haskell-2.7.0.0 or later (i.e., GHC 7.4 or later),
then derive-functions can be used with data family instances (which requires the
-XTypeFamilies extension). To do so, pass the Name of a data or newtype instance
constructor (NOT a data family name!) to deriveFoldable. Note that the
generated code may require the -XFlexibleInstances extension. Example:
{-# LANGUAGE FlexibleInstances, TemplateHaskell, TypeFamilies #-}
import Data.Deriving
class AssocClass a b where
data AssocData a b
instance AssocClass Int b where
data AssocData Int b = AssocDataInt1 Int
| AssocDataInt2 b
$(deriveFunctor 'AssocDataInt1) -- instance Functor (AssocData Int) where ...
-- Alternatively, one could use $(deriveFunctor 'AssocDataInt2)
derive-functions in deriving-compat fall into one of three categories:
- Category 0: Typeclasses with an argument of kind
*. (deriveEq,deriveOrd,deriveRead,deriveShow) - Category 1: Typeclasses with an argument of kind
* -> *, That is, a datatype with such an instance must have at least one type variable, and the last type variable must be of kind*. (deriveEq1,deriveFoldable,deriveFunctor,deriveOrd1,deriveRead1,deriveShow1,deriveTraversable) - Category 2: Typeclasses with an argument of kind
* -> * -> *. That is, a datatype with such an instance must have at least two type variables, and the last two type variables must be of kind*. (deriveEq2,deriveOrd2,deriveRead2,deriveShow2)
Note that there are some limitations to derive-functions:
- The
Nameargument must not be of a type synonym. - Type variables (other than the last ones) are assumed to require typeclass
constraints. The constraints are different depending on the category. For example,
for Category 0 functions, other type variables of kind
*are assumed to be constrained by that typeclass. As an example:
data Foo a = Foo a $(deriveEq ''Foo)
will result in a generated instance of:
instance Eq a => Eq (Foo a) where ...
If you do not want this behavior, use a make- function instead.
- For Category 1 and 2 functions, if you are using the
-XDatatypeContextsextension, a constraint cannot mention the last type variables. For example,data Illegal a where I :: Ord a => a -> Illegal acannot have a derivedFunctorinstance. - For Category 1 and 2 functions, if one of the last type variables is used within a
constructor field's type, it must only be used in the last type arguments. For
example,
data Legal a = Legal (Either Int a)can have a derivedFunctorinstance, butdata Illegal a = Illegal (Either a Int)cannot. - For Category 1 and 2 functions, data family instances must be able to eta-reduce the last type variables. In other words, if you have a instance of the form:
data family Family a1 ... an t1 ... tn data instance Family e1 ... e2 v1 ... vn = ...
where t1, ..., tn are the last type variables, then the following conditions
must hold:
v1, ...,vnmust be type variables.v1, ...,vnmust not be mentioned in any ofe1, ...,e2.
make- functions
Functions prefixed with make- are similar to derive-functions in that they also
generate code, but make-functions in particular generate the expression for a
particular typeclass method. For example:
{-# LANGUAGE TemplateHaskell #-}
import Data.Deriving
data Pair a = Pair a a
instance Functor Pair where
fmap = $(makeFmap ''Pair)
In this example, makeFmap will splice in the appropriate lambda expression which
implements fmap for Pair.
make-functions are subject to all the restrictions of derive-functions listed
above save for one exception: the datatype need not be an instance of a particular
typeclass. There are some scenarios where this might be preferred over using a
derive-function. For example, you might want to map over a Pair value
without explicitly having to make it an instance of Functor.
Another use case for make-functions is sophisticated data types—that is, an
expression for which a derive-function would infer the wrong instance context.
Consider the following example:
data Proxy a = Proxy
$(deriveEq ''Proxy)
This would result in a generated instance of:
instance Eq a => Eq (Proxy a) where ...
This compiles, but is not what we want, since the Eq a constraint is completely
unnecessary. Another scenario in which derive-functions fail is when you
have something like this:
newtype HigherKinded f a b = HigherKinded (f a b)
$(deriveFunctor ''HigherKinded)
Ideally, this would produce HigherKinded (f a) as its instance context, but sadly,
the Template Haskell type inference machinery used in deriving-compat is not smart
enough to figure that out. Nevertheless, make-functions provide a valuable
backdoor for these sorts of scenarios:
{-# LANGUAGE FlexibleContexts, TemplateHaskell #-}
import Data.Foldable.Deriving
data Proxy a = Proxy
newtype HigherKinded f a b = HigherKinded (f a b)
instance Eq (Proxy a) where
(==) = $(makeEq ''Proxy)
instance Functor (f a) => Functor (HigherKinded f a) where
fmap = $(makeFmap ''HigherKinded)