Functor package:yaya

This should probably be a separate library, but it provides a number of functor type classes between various categories.
A functor from the category of endofunctors to *Hask*. The D is meant to be a mnemonic for “down”, as we’re “lowering” from endofunctors to types.
An endofunctor in the category of endofunctors. NB: This is similar to MFunctor / hoist from mmorph, but without the Monad constraint on f.
Rules of renaming data names
Extract a pattern functor and relevant instances from a simply recursive type. e.g.
data Expr a
= Lit a
| Add (Expr a) (Expr a)
| Expr a :* [Expr a]
deriving stock (Show)

extractPatternFunctor defaultRules ''Expr
will create
data ExprF a x
= LitF a
| AddF x x
| x :*$ [x]
deriving stock (Functor, Foldable, Traversable)

instance Projectable (->) (Expr a) (ExprF a) where
project (Lit x)   = LitF x
project (Add x y) = AddF x y
project (x :* y)  = x :*$ y

instance Steppable (->) (Expr a) (ExprF a) where
embed (LitF x)   = Lit x
embed (AddF x y) = Add x y
embed (x :*$ y)  = x :* y

instance Recursive (->) (Expr a) (ExprF a) where
cata φ = φ . fmap (cata φ) . project

instance Corecursive (->) (Expr a) (ExprF a) where
ana ψ = embed . fmap (ana ψ) . ψ
Notes:
  • extractPatternFunctor works properly only with ADTs. Existentials and GADTs aren't supported, as we don't try to do better than GHC's DeriveFunctor.
  • we always generate both Recursive and Corecursive instances, but one of these is always unsafe. In future, we should check the strictness of the recursive parameter and generate only the appropriate one (unless overridden by a rule).