module Control.Monad.Coroutine.Nested
(
EitherFunctor(..), eitherFunctor, mapNestedSuspension,
pogoStickNested,
NestWeaveStepper,
ChildFunctor(..), AncestorFunctor(..),
liftParent, liftAncestor
)
where
import Control.Monad (liftM)
import Control.Monad.Coroutine
data EitherFunctor l r x = LeftF (l x) | RightF (r x)
instance (Functor l, Functor r) => Functor (EitherFunctor l r) where
fmap f (LeftF l) = LeftF (fmap f l)
fmap f (RightF r) = RightF (fmap f r)
eitherFunctor :: (l x -> y) -> (r x -> y) -> EitherFunctor l r x -> y
eitherFunctor left _ (LeftF f) = left f
eitherFunctor _ right (RightF f) = right f
mapNestedSuspension :: (Functor s0, Functor s, Monad m) => (forall y. s y -> s' y) ->
Coroutine (EitherFunctor s0 s) m x -> Coroutine (EitherFunctor s0 s') m x
mapNestedSuspension f cort = Coroutine {resume= liftM map' (resume cort)}
where map' (Right r) = Right r
map' (Left (LeftF s)) = Left (LeftF $ fmap (mapNestedSuspension f) s)
map' (Left (RightF s)) = Left (RightF (f $ fmap (mapNestedSuspension f) s))
pogoStickNested :: forall s1 s2 m x. (Functor s1, Functor s2, Monad m) =>
(s2 (Coroutine (EitherFunctor s1 s2) m x) -> Coroutine (EitherFunctor s1 s2) m x)
-> Coroutine (EitherFunctor s1 s2) m x -> Coroutine s1 m x
pogoStickNested reveal t =
Coroutine{resume= resume t
>>= \s-> case s
of Right result -> return (Right result)
Left (LeftF s') -> return (Left (fmap (pogoStickNested reveal) s'))
Left (RightF c) -> resume (pogoStickNested reveal (reveal c))}
type NestWeaveStepper s0 s1 s2 m x y z = WeaveStepper (EitherFunctor s0 s1) (EitherFunctor s0 s2) s0 m x y z
class Functor c => ChildFunctor c where
type Parent c :: * -> *
wrap :: Parent c x -> c x
instance (Functor p, Functor s) => ChildFunctor (EitherFunctor p s) where
type Parent (EitherFunctor p s) = p
wrap = LeftF
class (Functor a, Functor d) => AncestorFunctor a d where
liftFunctor :: a x -> d x
instance Functor a => AncestorFunctor a a where
liftFunctor = id
instance (Functor a, ChildFunctor d, d' ~ Parent d, AncestorFunctor a d') => AncestorFunctor a d where
liftFunctor = wrap . (liftFunctor :: a x -> d' x)
liftParent :: forall m p c x. (Monad m, Functor p, ChildFunctor c, p ~ Parent c) => Coroutine p m x -> Coroutine c m x
liftParent = mapSuspension wrap
liftAncestor :: forall m a d x. (Monad m, Functor a, AncestorFunctor a d) => Coroutine a m x -> Coroutine d m x
liftAncestor = mapSuspension liftFunctor