proarrow-0.1.0.0: src/Proarrow/Profunctor/Instance/Fix.hs
-- | The fixed point of a profunctor: @'Fix' p@ is @p ':.:' 'Fix' p@ rolled up, with 'hylo' as the
-- accompanying hylomorphism combinator.
module Proarrow.Profunctor.Instance.Fix where
import Data.Functor.Const (Const (..))
import Proarrow.Category.Instance.Nat (Nat (..))
import Proarrow.Category.Instance.Prof (Prof (..))
import Proarrow.Category.Monoidal (MonoidalProfunctor (..))
import Proarrow.Category.Monoidal.Distributive (Cotraversable (..), Traversable (..))
import Proarrow.Category.Monoidal.Strength (Strong (..))
import Proarrow.Core (Profunctor (..), Promonad (..), (:~>), type (+->))
import Proarrow.Functor (Functor (..))
import Proarrow.Profunctor.Instance.Composition ((:.:) (..))
import Proarrow.Profunctor.Instance.Star (Star, pattern Star)
-- | The fixed point of a profunctor: @'Fix' p@ is @p ':.:' 'Fix' p@ rolled up ('In'\/'out'). Fold it
-- with 'cata', unfold it with 'ana', or both at once with 'hylo'.
type Fix :: k +-> k -> k +-> k
data Fix p a b where
In :: {out :: ~((p :.: Fix p) a b)} -> Fix p a b
instance (Profunctor p) => Profunctor (Fix p) where
dimap l r = In . dimap l r . out \\ l \\ r
r \\ In p = r \\ p
instance (Promonad p) => Promonad (Fix p) where
id = In (id :.: id)
qs . In (p :.: ps) = In (p :.: (qs . ps))
instance Functor Fix where
map n@Prof{} = Prof (In . unProf (unNat (map n) . map (map n)) . out)
instance (MonoidalProfunctor p) => MonoidalProfunctor (Fix p) where
one = In one
In p ** In q = In (p ** q)
instance (Traversable p) => Traversable (Fix p) where
traverse (In pfp :.: r) = case traverse (pfp :.: r) of r' :.: pfp' -> r' :.: In pfp'
instance (Cotraversable p) => Cotraversable (Fix p) where
cotraverse (r :.: In pfp) = case cotraverse (r :.: pfp) of pfp' :.: r' -> In pfp' :.: r'
instance (Strong t p) => Strong t (Fix p) where
act @x (In p) = In (act @t @_ @x p)
hylo :: (Profunctor p, Profunctor a, Profunctor b) => (p :.: b :~> b) -> (a :~> p :.: a) -> a :~> b
hylo alg coalg = unProf go where go = Prof alg . map go . Prof coalg
cata :: (Profunctor p, Profunctor r) => (p :.: r :~> r) -> Fix p :~> r
cata alg = hylo alg out
ana :: (Profunctor p, Profunctor r) => (r :~> p :.: r) -> r :~> Fix p
ana coalg = hylo In coalg
data ListF x l = Nil | Cons x l
instance Functor (ListF x) where
map _ Nil = Nil
map f (Cons x l) = Cons x (f l)
embed :: ListF x [x] -> [x]
embed Nil = []
embed (Cons x xs) = x : xs
project :: [x] -> ListF x [x]
project [] = Nil
project (x : xs) = Cons x xs
embed' :: Star (ListF x) :.: Star (Const [x]) :~> Star (Const [x])
embed' (Star f :.: Star g) = Star (Const . embed . map (getConst . g) . f)
project' :: Star (Const [x]) :~> Star (ListF x) :.: Star (Const [x])
project' (Star f) = Star (project . getConst . f) :.: Star Const
toList :: Fix (Star (ListF x)) :~> Star (Const [x])
toList = cata embed'
fromList :: Star (Const [x]) :~> Fix (Star (ListF x))
fromList = ana project'