| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Control.Monad.CoComonad
Description
Monad transformer from Comonad.
This module provides the CoT monad transformer, which adds a "comonadic context"
to another monad.
What does CoT do?
For any Comonad f and Monad g, CoT f g is a monad that combines the original
effect of the monad g with the ability to use the comonad f as a context. For example:
CoT (is a monad with theEnve) ggeffect and access to a value of typee.- This is exactly what
provides, and in fact,ReaderTe gCoT (Env e) gis isomorphic toReaderT e g: seefromReaderTandtoReaderT.
- This is exactly what
CoT (is a monad with theStores) ggeffect and access to a context that holds a store ofsvalues, which can be queried or updated.- This corresponds exactly to what
provides, and indeed,StateTs gCoT (Store s) gis isomorphic toStateT s g: seefromStateTandtoStateT.
- This corresponds exactly to what
- Similarly,
CoT (is isomorphic toTracedm) g.WriterTm g
The "contextual" effects introduced by CoT can be composed freely. Any nested use of the
CoT monad transformer can be flattened into a single layer using the Day functor to
combine the contexts:
uncurryCoT :: Functor g => CoT f1 (CoT f2 g) ~> CoT (Day f1 f2) g curryCoT :: Functor g => CoT (Day f1 f2) g ~> CoT f1 (CoT f2 g)
Relation to other types
As a Functor, CoT f g is isomorphic to the type.
However, since Curried f gCurried has an Applicative instance that is not compatible
with the Monad instance of CoT, a new type was necessary to support the monad
behavior described here.
The non-transformer version, , is isomorphic to the
Co f type from the Control.Monad.Co module
(which is actually the source of inspiration for this module!).Co f
The name collision is unfortunate — the author has not yet decided on a final name for this monad transformer. Suggestions are welcome!
For category theory nerds
The construction of monad CoT f g, given Comonad f and Monad g,
can be explained via Kleisli category.
Recall that providing a Monad instance for a functor m is equivalent to
providing a Category (Kleisli m) instance.
-- The type of Kleisli category morphisms
newtype Kleisli m a b = Kl { runKl :: a -> m b }
-- Derive Category (Kleisli m) from Monad m
instance Monad m => Category (Kleisli m) where
id :: Kleisli m a a
id = Kl return
(.) :: Kleisli m b c -> Kleisli m a b -> Kleisli m a c
Kl f . Kl g = Kl (f <=< g)
-- Derive Monad m from Category (Kleisli m)
-- (pseudocode, can't be real Haskell)
instance Category (Kleisli m) => Monad m where
return = runKl id
ma >>= k = runKl (Kl k . Kl (const ma)) ()
Kleisli (CoT f g) is isomorphic to the following Arr f g.
type Arr f g a b = forall r. (a, f r) -> g (b, r)
Here's the transformations showing the isomorphism between Kleisli (CoT f g) and Arr f g.
Kleisli (CoT f g) a b ≅ a -> CoT f g b ≅ a -> ∀r. f r -> g (b, r) ≅ ∀r. a -> f r -> g (b, r) ≅ ∀r. (a, f r) -> g (b, r) ~ Arr f g a b
Arr f g can be made into Category with the following identity and composition.
The Monad (CoT f g) instance is the one derived from this construction.
idArr :: (Comonad f, Monad g) => Arr f g a a idArr (a, fr) = pure (a, extract fr) compArr :: (Comonad f, Monad g) => Arr f g a b -> Arr f g b c -> Arr f g a c compArr t u (a, fr) = t (a, duplicate fr) >>= u
Diagramatically, idArr is the following composite
\[ \require{AMScd} \begin{CD} (a, \_) \circ f @>>{\mathop{\mathtt{fmap}} \mathop{\mathtt{extract}}}> (a, \_) @>>{\mathtt{pure}}> g \circ (a, \_) \end{CD} \]
and compArr t u is the following composite.
\[ \require{AMScd} \begin{CD} (a, \_) \circ f @>>{\mathop{\mathtt{fmap}} \mathop{\mathtt{duplicate}}}> (a, \_) \circ f \circ f @>>{t}> g \circ (b, \_) \circ f @>>{\mathop{\mathtt{fmap}} u}> g \circ g \circ (c, \_) @>>{\mathop{\mathtt{join}}}> g \circ (c, \_) \end{CD} \]
Proving category laws for (idArr, compArr) will be simple enough.
Synopsis
- newtype CoT (f :: Type -> Type) (g :: Type -> Type) a = CoT {
- runCoT :: forall r. f r -> g (a, r)
- contrahoist :: forall f k (g :: Type -> Type) a. (forall x. f x -> k x) -> CoT k g a -> CoT f g a
- elimCoT :: forall (f :: Type -> Type) (g :: Type -> Type). (Applicative f, Functor g) => CoT f g ~> g
- curryCoT :: forall (g :: Type -> Type) (f1 :: Type -> Type) (f2 :: Type -> Type). Functor g => CoT (Day f1 f2) g ~> CoT f1 (CoT f2 g)
- uncurryCoT :: forall (g :: Type -> Type) (f1 :: Type -> Type) (f2 :: Type -> Type). Functor g => CoT f1 (CoT f2 g) ~> CoT (Day f1 f2) g
- eitherCoT :: forall (f1 :: Type -> Type) (g :: Type -> Type) (f2 :: Type -> Type) x. Product (CoT f1 g) (CoT f2 g) x -> CoT (Sum f1 f2) g x
- uneitherCoT :: forall (f1 :: Type -> Type) (f2 :: Type -> Type) (g :: Type -> Type) x. CoT (Sum f1 f2) g x -> Product (CoT f1 g) (CoT f2 g) x
- toReaderT :: forall (g :: Type -> Type) e a. Monad g => CoT (Env e) g a -> ReaderT e g a
- toWriterT :: forall (g :: Type -> Type) m a. Monad g => CoT (Traced m) g a -> WriterT m g a
- toStateT :: forall (g :: Type -> Type) s a. Monad g => CoT (Store s) g a -> StateT s g a
- fromReaderT :: forall e (f :: Type -> Type) (g :: Type -> Type) a. (ComonadEnv e f, Monad g) => ReaderT e g a -> CoT f g a
- fromWriterT :: forall m (f :: Type -> Type) (g :: Type -> Type) a. (ComonadTraced m f, Monad g) => WriterT m g a -> CoT f g a
- fromStateT :: forall s (f :: Type -> Type) (g :: Type -> Type) a. (ComonadStore s f, Monad g) => StateT s g a -> CoT f g a
- asking :: forall e (f :: Type -> Type) (g :: Type -> Type). (ComonadEnv e f, Monad g) => CoT f g e
- telling :: forall m (f :: Type -> Type) (g :: Type -> Type). (Monoid m, ComonadTraced m f, Monad g) => m -> CoT f g ()
- stating :: forall s (f :: Type -> Type) (g :: Type -> Type) a. (ComonadStore s f, Monad g) => (s -> (a, s)) -> CoT f g a
- toCurried :: forall (g :: Type -> Type) (f :: Type -> Type). Functor g => CoT f g ~> Curried f g
- fromCurried :: forall (f :: Type -> Type) (g :: Type -> Type). Functor f => Curried f g ~> CoT f g
- type Co (f :: Type -> Type) = CoT f Identity
- co :: (forall r. f r -> (a, r)) -> Co f a
- runCo :: Co f a -> f r -> (a, r)
- generalize :: Monad m => Identity a -> m a
- toCodensityCo :: forall (f :: Type -> Type). Functor f => Co f ~> Co f
- fromCodensityCo :: forall (f :: Type -> Type). Functor f => Co f ~> Co f
The CoT monad transformer
newtype CoT (f :: Type -> Type) (g :: Type -> Type) a Source #
CoT f g is a Monad which is based on Monad g but can use Comonad f
as a context.
Instances
| MFunctor (CoT f :: (Type -> Type) -> Type -> Type) Source # | |
| Comonad f => MonadTrans (CoT f) Source # | |
Defined in Control.Monad.CoComonad | |
| (Comonad f, MonadIO g) => MonadIO (CoT f g) Source # | |
Defined in Control.Monad.CoComonad | |
| (Comonad f, Monad g) => Applicative (CoT f g) Source # | |
| Functor g => Functor (CoT f g) Source # | |
| (Comonad f, Monad g) => Monad (CoT f g) Source # | |
Manipulating comonadic part
contrahoist :: forall f k (g :: Type -> Type) a. (forall x. f x -> k x) -> CoT k g a -> CoT f g a Source #
Change of the Comonad part.
contrahoist φ is a monad morphism CoT k g ~> CoT f g if φ :: f ~> k
is a comonad morphism.
elimCoT :: forall (f :: Type -> Type) (g :: Type -> Type). (Applicative f, Functor g) => CoT f g ~> g Source #
When the context f can be constructed as pure x : f a,
CoT f can be removed by supplying the "pure" context.
There are two notable special cases of elimCoT:
-- If the context f is Identity comonad,elimCoTis monad isomorphism and -- is the inverse oflift. elimCoT :: (Functor g) => CoTIdentityg ~> g
-- If the context f is NonEmpty comonad,elimCoTis monad morphism, -- andelimCoT . lift = idholds. elimCoT :: (Functor g) => CoTNonEmptyg ~> g
curryCoT :: forall (g :: Type -> Type) (f1 :: Type -> Type) (f2 :: Type -> Type). Functor g => CoT (Day f1 f2) g ~> CoT f1 (CoT f2 g) Source #
The inverse of uncurryCo.
uncurryCoT :: forall (g :: Type -> Type) (f1 :: Type -> Type) (f2 :: Type -> Type). Functor g => CoT f1 (CoT f2 g) ~> CoT (Day f1 f2) g Source #
Nesting of CoT f1 and CoT f2 can be represented as a single CoT (Day f1 f2) using
Day to combine two comonads.
This is also a monad isomorphism.
eitherCoT :: forall (f1 :: Type -> Type) (g :: Type -> Type) (f2 :: Type -> Type) x. Product (CoT f1 g) (CoT f2 g) x -> CoT (Sum f1 f2) g x Source #
Product of CoT into the same monad is CoT from the sum of comonads.
Compare it with either function:
either :: (a -> c) -> (b -> c) -> (Either a b -> c) either' :: (a -> c, b -> c) -> (Either a b -> c)
eitherCoT is a monad isomorphism (witnessed by uneitherCoT.)
uneitherCoT :: forall (f1 :: Type -> Type) (f2 :: Type -> Type) (g :: Type -> Type) x. CoT (Sum f1 f2) g x -> Product (CoT f1 g) (CoT f2 g) x Source #
The inverse of eitherCoT.
Representing Reader, Writer, or State effects
toWriterT :: forall (g :: Type -> Type) m a. Monad g => CoT (Traced m) g a -> WriterT m g a Source #
fromReaderT :: forall e (f :: Type -> Type) (g :: Type -> Type) a. (ComonadEnv e f, Monad g) => ReaderT e g a -> CoT f g a Source #
fromWriterT :: forall m (f :: Type -> Type) (g :: Type -> Type) a. (ComonadTraced m f, Monad g) => WriterT m g a -> CoT f g a Source #
fromStateT :: forall s (f :: Type -> Type) (g :: Type -> Type) a. (ComonadStore s f, Monad g) => StateT s g a -> CoT f g a Source #
asking :: forall e (f :: Type -> Type) (g :: Type -> Type). (ComonadEnv e f, Monad g) => CoT f g e Source #
telling :: forall m (f :: Type -> Type) (g :: Type -> Type). (Monoid m, ComonadTraced m f, Monad g) => m -> CoT f g () Source #
stating :: forall s (f :: Type -> Type) (g :: Type -> Type) a. (ComonadStore s f, Monad g) => (s -> (a, s)) -> CoT f g a Source #
Conversion
toCurried :: forall (g :: Type -> Type) (f :: Type -> Type). Functor g => CoT f g ~> Curried f g Source #
As a mere Functor, CoT f g is isomorphic to .Curried f g
fromCurried :: forall (f :: Type -> Type) (g :: Type -> Type). Functor f => Curried f g ~> CoT f g Source #
The inverse of toCurried
Non-transformer version
generalize :: Monad m => Identity a -> m a #
A function that generalizes the Identity base monad to be any monad.