Data.Bifunctor.TH

bifunctors-5.4.2: Bifunctors

Copyright | (C) 2008-2016 Edward Kmett, (C) 2015-2016 Ryan Scott
License | BSD-style (see the file LICENSE)
Maintainer | Edward Kmett <ekmett@gmail.com>
Stability | provisional
Portability | portable
Safe Haskell | Unsafe
Language | Haskell98

Data.Bifunctor.TH

Contents

- `derive`- functions
- `Bifoldable`
- `Bitraversable`

Description

Functions to mechanically derive `Bifunctor`, `Bifoldable`, or `Bitraversable` instances, or to splice their functions directly into source code. You need to enable the `TemplateHaskell` language extension in order to use this module.

Synopsis

- deriveBifunctor :: Name -> Q [Dec]
- makeBimap :: Name -> Q Exp
- deriveBifoldable :: Name -> Q [Dec]
- makeBifold :: Name -> Q Exp
- makeBifoldMap :: Name -> Q Exp
- makeBifoldr :: Name -> Q Exp
- makeBifoldl :: Name -> Q Exp
- deriveBitraversable :: Name -> Q [Dec]
- makeBitraverse :: Name -> Q Exp
- makeBisequenceA :: Name -> Q Exp
- makeBimapM :: Name -> Q Exp
- makeBisequence :: Name -> Q Exp

# `derive`- functions

`deriveBifunctor`, `deriveBifoldable`, and `deriveBitraversable` automatically generate their respective class instances for a given data type, newtype, or data family instance that has at least two type variable. Examples:

    {-# LANGUAGE TemplateHaskell #-}
    import Data.Bifunctor.TH

    data Pair a b = Pair a b
    $(deriveBifunctor ''Pair) -- instance Bifunctor Pair where ...

    data WrapLeftPair f g a b = WrapLeftPair (f a) (g a b)
    $(deriveBifoldable ''WrapLeftPair)
    -- instance (Foldable f, Bifoldable g) => Bifoldable (WrapLeftPair f g) where ...

If you are using `template-haskell-2.7.0.0` or later (i.e., GHC 7.4 or later), the `derive` functions can be used 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 a `derive` function. Note that the generated code may require the `-XFlexibleInstances` extension. Example:

    {-# LANGUAGE FlexibleInstances, TemplateHaskell, TypeFamilies #-}
    import Data.Bifunctor.TH

    class AssocClass a b c where
        data AssocData a b c
    instance AssocClass Int b c where
        data AssocData Int b c = AssocDataInt1 Int | AssocDataInt2 b c
    $(deriveBitraversable 'AssocDataInt1) -- instance Bitraversable (AssocData Int) where ...
    -- Alternatively, one could use $(deriveBitraversable 'AssocDataInt2)

Note that there are some limitations:

- The `Name` argument to a `derive` function must not be a type synonym.
- With a `derive` function, the last two type variables must both be of kind `*`. Other type variables of kind `* -> *` are assumed to require a `Functor`, `Foldable`, or `Traversable` constraint (depending on which `derive` function is used), and other type variables of kind `* -> * -> *` are assumed to require an `Bifunctor`, `Bifoldable`, or `Bitraversable` constraint. If your data type doesn't meet these assumptions, use a `make` function.
- If using the `-XDatatypeContexts`, `-XExistentialQuantification`, or `-XGADTs` extensions, a constraint cannot mention either of the last two type variables. For example, `data Illegal2 a b where I2 :: Ord a => a -> b -> Illegal2 a b` cannot have a derived `Bifunctor` instance.
- If either of the last two type variables is used within a constructor argument's type, it must only be used in the last two type arguments. For example, `data Legal a b = Legal (Int, Int, a, b)` can have a derived `Bifunctor` instance, but `data Illegal a b = Illegal (a, b, a, b)` cannot.
- Data family instances must be able to eta-reduce the last two type variables. In other words, if you have a instance of the form:

     data family Family a1 ... an t1 t2
     data instance Family e1 ... e2 v1 v2 = ...

Then the following conditions must hold:

1. `v1` and `v2` must be distinct type variables.
2. Neither `v1` not `v2` must be mentioned in any of `e1`, ..., `e2`.

There may be scenarios in which you want to, say, `bimap` over an arbitrary data type or data family instance without having to make the type an instance of `Bifunctor`. For these cases, this module provides several functions (all prefixed with `make`-) that splice the appropriate lambda expression into your source code.

This is particularly useful for creating instances for sophisticated data types. For example, `deriveBifunctor` cannot infer the correct type context for `newtype HigherKinded f a b c = HigherKinded (f a b c)`, since `f` is of kind `* -> * -> * -> *`. However, it is still possible to create a `Bifunctor` instance for `HigherKinded` without too much trouble using `makeBimap`:

    {-# LANGUAGE FlexibleContexts, TemplateHaskell #-}
    import Data.Bifunctor
    import Data.Bifunctor.TH

    newtype HigherKinded f a b c = HigherKinded (f a b c)

    instance Bifunctor (f a) => Bifunctor (HigherKinded f a) where
        bimap = $(makeBimap ''HigherKinded)

deriveBifunctor :: Name -> Q [Dec] #

Generates a `Bifunctor` instance declaration for the given data type or data family instance.

makeBimap :: Name -> Q Exp #

Generates a lambda expression which behaves like `bimap` (without requiring a `Bifunctor` instance).

# `Bifoldable`

deriveBifoldable :: Name -> Q [Dec] #

Generates a `Bifoldable` instance declaration for the given data type or data family instance.

makeBifold :: Name -> Q Exp #

Generates a lambda expression which behaves like `bifold` (without requiring a `Bifoldable` instance).

makeBifoldMap :: Name -> Q Exp #

Generates a lambda expression which behaves like `bifoldMap` (without requiring a `Bifoldable` instance).

makeBifoldr :: Name -> Q Exp #

Generates a lambda expression which behaves like `bifoldr` (without requiring a `Bifoldable` instance).

makeBifoldl :: Name -> Q Exp #

Generates a lambda expression which behaves like `bifoldl` (without requiring a `Bifoldable` instance).

# `Bitraversable`

deriveBitraversable :: Name -> Q [Dec] #

Generates a `Bitraversable` instance declaration for the given data type or data family instance.

makeBitraverse :: Name -> Q Exp #

Generates a lambda expression which behaves like `bitraverse` (without requiring a `Bitraversable` instance).

makeBisequenceA :: Name -> Q Exp #

Generates a lambda expression which behaves like `bisequenceA` (without requiring a `Bitraversable` instance).

makeBimapM :: Name -> Q Exp #

Generates a lambda expression which behaves like `bimapM` (without requiring a `Bitraversable` instance).

makeBisequence :: Name -> Q Exp #

Generates a lambda expression which behaves like `bisequence` (without requiring a `Bitraversable` instance).