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:
data Expr a = Lit a | Add (Expr a) (Expr a) | Expr a :* [Expr a]; makeBaseFunctor ''Expr:t AddFAddF :: r -> r -> ExprF a r
data Rose f a = Rose a (f (Rose f a)); makeBaseFunctor $ asQ [d| instance Functor f => Recursive (Rose f a) |]:t RoseFRoseF :: a -> f r -> RoseF f a r
let rose = Rose 1 (Just (Rose 2 (Just (Rose 3 Nothing))))cata (\(RoseF x f) -> x + maybe 0 id f) rose6
Methods
makeBaseFunctor :: a -> DecsQmakeBaseFunctorWith :: BaseRules -> a -> DecsQBuild base functor with a custom configuration.
Instances4MakeBaseFunctor
MakeBaseFunctor DecDefined in recursion-schemes-5.2.3 · Data.Functor.Foldable.THExpects declarations of Recursive or Corecursive instances, e.g.
makeBaseFunctor [d| instance Functor f => Recursive (Rose f a) |]This way we can provide a context for generated instances. Note that this instance's makeBaseFunctor still generates all of Base type instance, Recursive and Corecursive instances.
MakeBaseFunctor NameDefined in recursion-schemes-5.2.3 · Data.Functor.Foldable.THMakeBaseFunctor a => MakeBaseFunctor (Q a)Defined in recursion-schemes-5.2.3 · Data.Functor.Foldable.THMakeBaseFunctor a => MakeBaseFunctor [a]Defined in recursion-schemes-5.2.3 · Data.Functor.Foldable.TH