bound-2.0.6: Making de Bruijn Succ Less
Copyright(C) 2012-2013 Edward Kmett
LicenseBSD-style (see the file LICENSE)
MaintainerEdward Kmett <ekmett@gmail.com>
Stabilityexperimental
Portabilityportable
Safe HaskellSafe-Inferred
LanguageHaskell2010

Bound.TH

Description

This is a Template Haskell module for deriving Applicative and Monad instances for data types.

Synopsis

Documentation

makeBound :: Name -> DecsQ Source #

Use to automatically derive Applicative and Monad instances for your datatype.

Also works for components that are lists or instances of Functor, but still does not work for a great deal of other things.

The deriving-compat package may be used to derive the Show1 and Read1 instances. Note that due to Template Haskell staging restrictions, we must define these instances within the same TH splice as the Show and Read instances. (This is needed for GHC 9.6 and later, where Show and Read are quantified superclasses of Show1 and Read1, respectively.)

{-# LANGUAGE DeriveFunctor      #-}
{-# LANGUAGE TemplateHaskell    #-}

import Bound                (Scope, makeBound)
import Data.Functor.Classes (Show1, Read1, showsPrec1, readsPrec1)
import Data.Deriving        (deriveShow1, deriveRead1)

data Exp a
  = V a
  | App (Exp a) (Exp a)
  | Lam (Scope () Exp a)
  | ND [Exp a]
  | I Int
  deriving (Functor)

makeBound ''Exp

concat $ sequence
  [ deriveShow1 ''Exp
  , deriveRead1 ''Exp
  , [d| instance Read a => Read (Exp a) where readsPrec = readsPrec1
        instance Show a => Show (Exp a) where showsPrec = showsPrec1
      |]
  ]

and in GHCi

ghci> :set -XDeriveFunctor
ghci> :set -XTemplateHaskell
ghci> import Bound                (Scope, makeBound)
ghci> import Data.Functor.Classes (Show1, Read1, showsPrec1, readsPrec1)
ghci> import Data.Deriving        (deriveShow1, deriveRead1)
ghci> :{
ghci| data Exp a = V a | App (Exp a) (Exp a) | Lam (Scope () Exp a) | ND [Exp a] | I Int deriving (Functor)
ghci| makeBound ''Exp
ghci| fmap concat $ sequence [deriveShow1 ''Exp, deriveRead1 ''Exp, [d| instance Read a => Read (Exp a) where { readsPrec = readsPrec1 }; instance Show a => Show (Exp a) where { showsPrec = showsPrec1 } |]]
ghci| :}

The Eq and Ord instances can be derived similarly:

import Data.Functor.Classes (Eq1, Ord1, eq1, compare1)
import Data.Deriving        (deriveEq1, deriveOrd1)

fmap concat $ sequence
  [ deriveEq1 ''Exp
  , deriveOrd1 ''Exp
  , [d| instance Eq a => Eq (Exp a) where (==) = eq1
        instance Ord a => Ord (Exp a) where compare = compare1
      |]
  ]

or in GHCi:

ghci> import Data.Functor.Classes (Eq1, Ord1, eq1, compare1)
ghci> import Data.Deriving        (deriveEq1, deriveOrd1)
ghci> :{
ghci| fmap concat $ sequence [deriveEq1 ''Exp, deriveOrd1 ''Exp, [d| instance Eq a => Eq (Exp a) where { (==) = eq1 }; instance Ord a => Ord (Exp a) where { compare = compare1 } |]]
ghci| :}

We cannot automatically derive Eq and Ord using the standard GHC mechanism, because instances require Exp to be a Monad:

instance (Monad f, Eq b, Eq1 f, Eq a)    => Eq (Scope b f a)
instance (Monad f, Ord b, Ord1 f, Ord a) => Ord (Scope b f a)