{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE UnicodeSyntax #-} -- | Several extensions to Edward Kmett's recursion schemes package. The monadic -- recursion schemes and exotic recursion schemes should be stable, but the -- recursion schemes for interdependent data type (and their attendant -- typeclasses) are experimental. module Data.Functor.Foldable.Exotic ( -- * Monadic recursion schemes cataM , anaM , hyloM -- * Recursion schemes for interdependent data types , dendro , scolio , chema -- * Exotic recursion schemes , dicata , micro , mutu -- * Data type for transformations , Trans -- * Helper functions , finish ) where import Control.Arrow import Control.Composition import Control.Lens import Control.Monad import Data.Functor.Foldable dock :: (Eq a) => [a] -> a dock [x] = x dock [] = undefined dock (x:ys@(y:_)) | x == y = y | otherwise = dock ys -- | Helper function to force recursion. This can be used alongside 'dendro' to -- simplify writing a 'Trans' finish :: (Eq a) => (a -> a) -> a -> a finish = dock .* iterate -- | A map of \\( F \\)-algebras (pseudoprism) type Trans s a = ∀ f. Functor f => (f a -> a) -> f s -> s -- | Mutumorphism mutu :: Recursive t => (Base t (b, a) -> b) -> (Base t (b, a) -> a) -> t -> a mutu f g = snd . cata (f &&& g) -- | Entangle two hylomorphisms. scolio :: (Functor f, Functor g) => ((f b -> b) -> Trans b b) -- ^ A pseudoprism parametric in an \\( F \\)-algebra that allows @b@ to inspect itself. -> ((a -> f a) -> Lens' a a) -- ^ A lens parametric in an \\( F \\)-coalgebra that allows @b@ to inspect itself. -> (g b -> b) -- ^ A @g@-algebra -> (a -> g a) -- ^ A @g@-coalgebra -> (f b -> b) -- ^ An @f@-algebra -> (a -> f a) -- ^ An @f@-coalgebra -> a -> b scolio p l alg coalg alg' coalg' = hylo (p alg' alg) (l coalg' coalg) -- Entangle two anamorphisms. chema :: (Corecursive t', Functor f) => ((a -> f a) -> Lens' b b) -- ^ A lens parametric in an \\( F \\)-coalgebra that allows @b@ to inspect itself. -> (a -> f a) -- ^ A @(Base t)@-coalgebra -> (b -> Base t' b) -- ^ A @(Base t')@-coalgebra -> b -> t' chema = (ana .*) -- | A dendromorphism entangles two catamorphisms dendro :: (Recursive t', Functor f) => ((f a -> a) -> Trans b b) -- ^ A pseudoprism parametric in an \\(F \\)-algebra that allows @b@ to inspect itself. -> (f a -> a) -- ^ A @(Base t)@-algebra -> (Base t' b -> b) -- ^ A @(Base t')@-algebra -> t' -> b dendro = (cata .*) -- | Catamorphism collapsing along two data types simultaneously. Basically a fancy zygomorphism. dicata :: (Recursive a) => (Base a (b, a) -> b) -> (Base a (b, a) -> a) -> a -> b dicata = fst .** (cata .* (&&&)) -- | A micromorphism is an Elgot algebra specialized to unfolding. micro :: (Corecursive a) => (b -> Either a (Base a b)) -> b -> a micro = elgot embed -- | A monadic catamorphism cataM :: (Recursive t, Traversable (Base t), Monad m) => (Base t a -> m a) -> (t -> m a) cataM phi = c where c = phi <=< (traverse c . project) -- | A monadic anamorphism anaM :: (Corecursive t, Traversable (Base t), Monad m) => (a -> m (Base t a)) -> (a -> m t) anaM psi = a where a = (fmap embed . traverse a) <=< psi -- | A monadic hylomorphism hyloM :: (Functor f, Monad m, Traversable f) => (f b -> m b) -> (a -> m (f a)) -> a -> m b hyloM phi psi = h where h = phi <=< traverse h <=< psi