| Copyright | (c) 2010-2011 Patrick Bahr |
|---|---|
| License | BSD3 |
| Maintainer | Patrick Bahr <[email protected]> |
| Stability | experimental |
| Portability | non-portable (GHC Extensions) |
| Safe Haskell | None |
| Language | Haskell98 |
Data.Comp.Derive
Contents
Description
This module contains functionality for automatically deriving boilerplate
code using Template Haskell. Examples include instances of Functor,
Foldable, and Traversable.
- derive :: [Name -> Q [Dec]] -> [Name] -> Q [Dec]
- class ShowF f where
- makeShowF :: Name -> Q [Dec]
- class ShowConstr f where
- showConstr :: f a -> String
- makeShowConstr :: Name -> Q [Dec]
- class EqF f where
- makeEqF :: Name -> Q [Dec]
- class EqF f => OrdF f where
- makeOrdF :: Name -> Q [Dec]
- class Functor f
- makeFunctor :: Name -> Q [Dec]
- class Foldable t
- makeFoldable :: Name -> Q [Dec]
- class (Functor t, Foldable t) => Traversable t
- makeTraversable :: Name -> Q [Dec]
- makeHaskellStrict :: Name -> Q [Dec]
- haskellStrict :: (Monad m, HaskellStrict f, f :<: g) => f (TermT m g) -> TermT m g
- haskellStrict' :: (Monad m, HaskellStrict f, f :<: g) => f (TermT m g) -> TermT m g
- class ArbitraryF f where
- arbitraryF' :: Arbitrary v => [(Int, Gen (f v))]
- arbitraryF :: Arbitrary v => Gen (f v)
- shrinkF :: Arbitrary v => f v -> [f v]
- makeArbitraryF :: Name -> Q [Dec]
- class Arbitrary a where
- makeArbitrary :: Name -> Q [Dec]
- class NFData a where
- rnf :: a -> ()
- makeNFData :: Name -> Q [Dec]
- class NFDataF f where
- makeNFDataF :: Name -> Q [Dec]
- smartConstructors :: Name -> Q [Dec]
- smartAConstructors :: Name -> Q [Dec]
- liftSum :: Name -> Q [Dec]
Documentation
derive :: [Name -> Q [Dec]] -> [Name] -> Q [Dec] Source
Helper function for generating a list of instances for a list of named
signatures. For example, in order to derive instances Functor and
ShowF for a signature Exp, use derive as follows (requires Template
Haskell):
$(derive [makeFunctor, makeShowF] [''Exp])
Derive boilerplate instances for compositional data type signatures.
ShowF
Signature printing. An instance ShowF f gives rise to an instance
Show (Term f).
makeShowF :: Name -> Q [Dec] Source
Derive an instance of ShowF for a type constructor of any first-order kind
taking at least one argument.
class ShowConstr f where Source
Constructor printing.
Methods
showConstr :: f a -> String Source
Instances
| (ShowConstr f, Show p) => ShowConstr ((:&:) f p) | |
| (ShowConstr f, ShowConstr g) => ShowConstr ((:+:) f g) |
makeShowConstr :: Name -> Q [Dec] Source
Derive an instance of showConstr for a type constructor of any first-order kind
taking at least one argument.
EqF
Signature equality. An instance EqF f gives rise to an instance
Eq (Term f).
Instances
| EqF [] | |
| EqF Maybe | |
| Eq a0 => EqF ((,) a) | |
| (Eq a0, Eq b0) => EqF ((,,) a b) | |
| (EqF f, EqF g) => EqF ((:+:) f g) |
|
| EqF f => EqF (Cxt h f) | |
| (Eq a0, Eq b0, Eq c0) => EqF ((,,,) a b c) | |
| (Eq a0, Eq b0, Eq c0, Eq d0) => EqF ((,,,,) a b c d) | |
| (Eq a0, Eq b0, Eq c0, Eq d0, Eq e0) => EqF ((,,,,,) a b c d e) | |
| (Eq a0, Eq b0, Eq c0, Eq d0, Eq e0, Eq f0) => EqF ((,,,,,,) a b c d e f) | |
| (Eq a0, Eq b0, Eq c0, Eq d0, Eq e0, Eq f0, Eq g0) => EqF ((,,,,,,,) a b c d e f g) | |
| (Eq a0, Eq b0, Eq c0, Eq d0, Eq e0, Eq f0, Eq g0, Eq h0) => EqF ((,,,,,,,,) a b c d e f g h) | |
| (Eq a0, Eq b0, Eq c0, Eq d0, Eq e0, Eq f0, Eq g0, Eq h0, Eq i0) => EqF ((,,,,,,,,,) a b c d e f g h i) |
makeEqF :: Name -> Q [Dec] Source
Derive an instance of EqF for a type constructor of any first-order kind
taking at least one argument.
OrdF
class EqF f => OrdF f where Source
Signature ordering. An instance OrdF f gives rise to an instance
Ord (Term f).
Instances
| OrdF [] | |
| OrdF Maybe | |
| Ord a0 => OrdF ((,) a) | |
| (Ord a0, Ord b0) => OrdF ((,,) a b) | |
| (OrdF f, OrdF g) => OrdF ((:+:) f g) |
|
| OrdF f => OrdF (Cxt h f) | |
| (Ord a0, Ord b0, Ord c0) => OrdF ((,,,) a b c) | |
| (Ord a0, Ord b0, Ord c0, Ord d0) => OrdF ((,,,,) a b c d) | |
| (Ord a0, Ord b0, Ord c0, Ord d0, Ord e0) => OrdF ((,,,,,) a b c d e) | |
| (Ord a0, Ord b0, Ord c0, Ord d0, Ord e0, Ord f0) => OrdF ((,,,,,,) a b c d e f) | |
| (Ord a0, Ord b0, Ord c0, Ord d0, Ord e0, Ord f0, Ord g0) => OrdF ((,,,,,,,) a b c d e f g) | |
| (Ord a0, Ord b0, Ord c0, Ord d0, Ord e0, Ord f0, Ord g0, Ord h0) => OrdF ((,,,,,,,,) a b c d e f g h) | |
| (Ord a0, Ord b0, Ord c0, Ord d0, Ord e0, Ord f0, Ord g0, Ord h0, Ord i0) => OrdF ((,,,,,,,,,) a b c d e f g h i) |
makeOrdF :: Name -> Q [Dec] Source
Derive an instance of OrdF for a type constructor of any first-order kind
taking at least one argument.
Functor
class Functor f
The Functor class is used for types that can be mapped over.
Instances of Functor should satisfy the following laws:
fmap id == id fmap (f . g) == fmap f . fmap g
The instances of Functor for lists, Maybe and IO
satisfy these laws.
Minimal complete definition
Instances
makeFunctor :: Name -> Q [Dec] Source
Derive an instance of Functor for a type constructor of any first-order
kind taking at least one argument.
Foldable
class Foldable t
Data structures that can be folded.
Minimal complete definition: foldMap or foldr.
For example, given a data type
data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)
a suitable instance would be
instance Foldable Tree where foldMap f Empty = mempty foldMap f (Leaf x) = f x foldMap f (Node l k r) = foldMap f l `mappend` f k `mappend` foldMap f r
This is suitable even for abstract types, as the monoid is assumed
to satisfy the monoid laws. Alternatively, one could define foldr:
instance Foldable Tree where foldr f z Empty = z foldr f z (Leaf x) = f x z foldr f z (Node l k r) = foldr f (f k (foldr f z r)) l
Instances
makeFoldable :: Name -> Q [Dec] Source
Derive an instance of Foldable for a type constructor of any first-order
kind taking at least one argument.
Traversable
class (Functor t, Foldable t) => Traversable t
Functors representing data structures that can be traversed from left to right.
Minimal complete definition: traverse or sequenceA.
A definition of traverse must satisfy the following laws:
- naturality
t .for every applicative transformationtraversef =traverse(t . f)t- identity
traverseIdentity = Identity- composition
traverse(Compose .fmapg . f) = Compose .fmap(traverseg) .traversef
A definition of sequenceA must satisfy the following laws:
- naturality
t .for every applicative transformationsequenceA=sequenceA.fmaptt- identity
sequenceA.fmapIdentity = Identity- composition
sequenceA.fmapCompose = Compose .fmapsequenceA.sequenceA
where an applicative transformation is a function
t :: (Applicative f, Applicative g) => f a -> g a
preserving the Applicative operations, i.e.
and the identity functor Identity and composition of functors Compose
are defined as
newtype Identity a = Identity a
instance Functor Identity where
fmap f (Identity x) = Identity (f x)
instance Applicative Indentity where
pure x = Identity x
Identity f <*> Identity x = Identity (f x)
newtype Compose f g a = Compose (f (g a))
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose x) = Compose (fmap (fmap f) x)
instance (Applicative f, Applicative g) => Applicative (Compose f g) where
pure x = Compose (pure (pure x))
Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)(The naturality law is implied by parametricity.)
Instances are similar to Functor, e.g. given a data type
data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)
a suitable instance would be
instance Traversable Tree where traverse f Empty = pure Empty traverse f (Leaf x) = Leaf <$> f x traverse f (Node l k r) = Node <$> traverse f l <*> f k <*> traverse f r
This is suitable even for abstract types, as the laws for <*>
imply a form of associativity.
The superclass instances should satisfy the following:
- In the
Functorinstance,fmapshould be equivalent to traversal with the identity applicative functor (fmapDefault). - In the
Foldableinstance,foldMapshould be equivalent to traversal with a constant applicative functor (foldMapDefault).
Instances
makeTraversable :: Name -> Q [Dec] Source
Derive an instance of Traversable for a type constructor of any
first-order kind taking at least one argument.
HaskellStrict
makeHaskellStrict :: Name -> Q [Dec] Source
Derive an instance of HaskellStrict for a type constructor of any
first-order kind taking at least one argument.
Arbitrary
class ArbitraryF f where Source
Signature arbitration. An instance ArbitraryF f gives rise to an instance
Arbitrary (Term f).
Minimal complete definition
Nothing
Methods
arbitraryF' :: Arbitrary v => [(Int, Gen (f v))] Source
arbitraryF :: Arbitrary v => Gen (f v) Source
Instances
makeArbitraryF :: Name -> Q [Dec] Source
Derive an instance of ArbitraryF for a type constructor of any
first-order kind taking at least one argument. It is necessary that
all types that are used by the data type definition are themselves
instances of Arbitrary.
class Arbitrary a where
Random generation and shrinking of values.
Minimal complete definition
Nothing
Methods
A generator for values of the given type.
shrink :: a -> [a]
Produces a (possibly) empty list of all the possible immediate shrinks of the given value. The default implementation returns the empty list, so will not try to shrink the value.
Most implementations of shrink should try at least three things:
- Shrink a term to any of its immediate subterms.
- Recursively apply
shrinkto all immediate subterms. - Type-specific shrinkings such as replacing a constructor by a simpler constructor.
For example, suppose we have the following implementation of binary trees:
data Tree a = Nil | Branch a (Tree a) (Tree a)
We can then define shrink as follows:
shrink Nil = [] shrink (Branch x l r) = -- shrink Branch to Nil [Nil] ++ -- shrink to subterms [l, r] ++ -- recursively shrink subterms [Branch x' l' r' | (x', l', r') <- shrink (x, l, r)]
There are a couple of subtleties here:
- QuickCheck tries the shrinking candidates in the order they
appear in the list, so we put more aggressive shrinking steps
(such as replacing the whole tree by
Nil) before smaller ones (such as recursively shrinking the subtrees). - It is tempting to write the last line as
[Branch x' l' r' | x' <- shrink x, l' <- shrink l, r' <- shrink r]but this is the wrong thing! It will force QuickCheck to shrinkx,landrin tandem, and shrinking will stop once one of the three is fully shrunk.
There is a fair bit of boilerplate in the code above.
We can avoid it with the help of some generic functions;
note that these only work on GHC 7.2 and above.
The function genericShrink tries shrinking a term to all of its
subterms and, failing that, recursively shrinks the subterms.
Using it, we can define shrink as:
shrink x = shrinkToNil x ++ genericShrink x
where
shrinkToNil Nil = []
shrinkToNil (Branch _ l r) = [Nil]genericShrink is a combination of subterms, which shrinks
a term to any of its subterms, and recursivelyShrink, which shrinks
all subterms of a term. These may be useful if you need a bit more
control over shrinking than genericShrink gives you.
A final gotcha: we cannot define shrink as simply
as this shrinks shrink x = Nil:genericShrink xNil to Nil, and shrinking will go into an
infinite loop.
If all this leaves you bewildered, you might try to begin with,
after deriving shrink = genericShrinkGeneric and Typeable for your type. However, if your data type has any
special invariants, you will need to check that genericShrink can't break those invariants.
Instances
class NFData a where
A class of types that can be fully evaluated.
Since: 1.1.0.0
Minimal complete definition
Nothing
Methods
rnf :: a -> ()
rnf should reduce its argument to normal form (that is, fully evaluate all sub-components), and then return '()'.
The default implementation of rnf is
rnf a = a `seq` ()
which may be convenient when defining instances for data types with no unevaluated fields (e.g. enumerations).
Instances
DeepSeq
Signature normal form. An instance NFDataF f gives rise to an instance
NFData (Term f).
makeNFDataF :: Name -> Q [Dec] Source
Derive an instance of NFDataF for a type constructor of any first-order
kind taking at least one argument.
Smart Constructors
smartConstructors :: Name -> Q [Dec] Source
Derive smart constructors for a type constructor of any first-order kind
taking at least one argument. The smart constructors are similar to the
ordinary constructors, but an inject is automatically inserted.
Smart Constructors w/ Annotations
smartAConstructors :: Name -> Q [Dec] Source
Derive smart constructors with products for a type constructor of any
parametric kind taking at least one argument. The smart constructors are
similar to the ordinary constructors, but an injectA is automatically
inserted.