{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
{- |
Handling monad morphisms.
-}
module LiveCoding.Cell.Monad where
-- essence-of-live-coding
import Control.Arrow (Arrow (arr), (>>>))
import Data.Data (Data)
import LiveCoding.Cell
-- | Apply a monad morphism that also transforms the output to a cell.
hoistCellOutput ::
(Monad m1, Monad m2) =>
(forall s. m1 (b1, s) -> m2 (b2, s)) ->
Cell m1 a b1 ->
Cell m2 a b2
hoistCellOutput morph = hoistCellKleisli_ (morph .)
-- | Apply a transformation of Kleisli morphisms to a cell.
hoistCellKleisli_ ::
(Monad m1, Monad m2) =>
(forall s. (a1 -> m1 (b1, s)) -> (a2 -> m2 (b2, s))) ->
Cell m1 a1 b1 ->
Cell m2 a2 b2
hoistCellKleisli_ morph = hoistCellKleisli (morph .)
-- | Apply a transformation of stateful Kleisli morphisms to a cell.
hoistCellKleisli ::
(Monad m1, Monad m2) =>
(forall s. (s -> a1 -> m1 (b1, s)) -> (s -> a2 -> m2 (b2, s))) ->
Cell m1 a1 b1 ->
Cell m2 a2 b2
hoistCellKleisli morph ArrM {..} =
ArrM
{ runArrM = (fmap fst .) $ ($ ()) $ morph $ const $ runArrM >>> fmap (,())
}
hoistCellKleisli morph Cell {..} =
Cell
{ cellStep = morph cellStep
, ..
}
{- | Apply a transformation of stateful Kleisli morphisms to a cell,
changing the state type.
-}
hoistCellKleisliStateChange ::
(Monad m1, Monad m2, (forall s. Data s => Data (t s))) =>
( forall s.
(s -> a1 -> m1 (b1, s)) ->
(t s -> a2 -> m2 (b2, t s))
) ->
(forall s. (s -> t s)) ->
Cell m1 a1 b1 ->
Cell m2 a2 b2
hoistCellKleisliStateChange morph init Cell {..} =
Cell
{ cellStep = morph cellStep
, cellState = init cellState
}
hoistCellKleisliStateChange morph init cell = hoistCellKleisliStateChange morph init $ toCell cell