HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Modulerecursion-schemes-5.2.3Haskell2010

Data.Functor.Foldable.TH

  • 1 type
  • 1 class
  • 4 values
classclass MakeBaseFunctor a where
#

Build base functor with a sensible default configuration.

e.g.

data Expr a
    = Lit a
    | Add (Expr a) (Expr a)
    | Expr a :* [Expr a]
  deriving (Show)

makeBaseFunctor ''Expr

will create

data ExprF a x
    = LitF a
    | AddF x x
    | x :*$ [x]
  deriving (Functor, Foldable, Traversable)

type instance Base (Expr a) = ExprF a

instance Recursive (Expr a) where
    project (Lit x)   = LitF x
    project (Add x y) = AddF x y
    project (x :* y)  = x :*$ y

instance Corecursive (Expr a) where
    embed (LitF x)   = Lit x
    embed (AddF x y) = Add x y
    embed (x :*$ y)  = x :* y

Notes:

makeBaseFunctor works properly only with ADTs. Existentials and GADTs aren't supported, as we don't try to do better than GHC's DeriveFunctor.

Allowing makeBaseFunctor to take both Names and Decs as an argument is why it exists as a method in a type class. For trickier data-types, like rose-tree (see also Cofree):

data Rose f a = Rose a (f (Rose f a))

we can invoke makeBaseFunctor with an instance declaration to provide needed context for instances. (c.f. StandaloneDeriving)

makeBaseFunctor [d| instance Functor f => Recursive (Rose f a) |]

will create

data RoseF f a r = RoseF a (f fr)
  deriving (Functor, Foldable, Traversable)

type instance Base (Rose f a) = RoseF f a

instance Functor f => Recursive (Rose f a) where
  project (Rose x xs) = RoseF x xs

instance Functor f => Corecursive (Rose f a) where
  embed (RoseF x xs) = Rose x xs

Some doctests:

Example1 expression
data Expr a = Lit a | Add (Expr a) (Expr a) | Expr a :* [Expr a]; makeBaseFunctor ''Expr
Example1 expression
:t AddFAddF :: r -> r -> ExprF a r
Example1 expression
data Rose f a = Rose a (f (Rose f a)); makeBaseFunctor $ asQ [d| instance Functor f => Recursive (Rose f a) |]
Example1 expression
:t RoseFRoseF :: a -> f r -> RoseF f a r
Example2 expressions
let rose = Rose 1 (Just (Rose 2 (Just (Rose 3 Nothing))))cata (\(RoseF x f) -> x + maybe 0 id f) rose6

Methods

Instances4MakeBaseFunctor
datadata BaseRules
#

Rules of renaming data names