% -*- LaTeX -*-
% $Id: Combined.lhs,v 1.16 2003/05/07 22:38:37 wlux Exp $
%
% Copyright (c) 1998-2003, Wolfgang Lux
% See LICENSE for the full license.
%
\nwfilename{Combined.lhs}
\section{Combined monads}\label{sec:combined-monads}
In this section we introduce combined monads which are parameterized
by another monads. This technique has been explored
in~\cite{KingWadler93:Combining} and very extensively
in~\cite{LiangHudakJones95:ModInterp}. The monad transformers used in
this report are mostly copied from the latter. Some restrictions were
necessary because Haskell~98 does not support multi-parameter type
classes. Especially, we cannot define generic lift operations because
they have to be parameterized over two monad classes. In addition, we
cannot define generic state and environment monad classes.
\begin{verbatim}
> module Combined where
> import Control.Monad
> import Control.Monad.Identity
\end{verbatim}
\subsection{State transformers}
The state transformer monad is defined as usual, except that the
result of the state transformer function is itself a monad. The
unparameterized version is defined by using the identity monad
\texttt{Id} for the base monad.
\begin{verbatim}
> newtype StateT s m a = StateT (s -> m (a,s))
> type St s = StateT s Identity
> unStateT :: StateT s m a -> (s -> m (a,s))
> unStateT (StateT st) = st
> instance Functor f => Functor (StateT s f) where
> fmap f (StateT st) = StateT (fmap (\(x,s') -> (f x,s')) . st)
> instance Monad m => Monad (StateT s m) where
> return x = StateT (\s -> return (x,s))
> StateT st >>= f = StateT (\s -> st s >>= \(x,s') -> unStateT (f x) s')
> fail msg = StateT (const (fail msg))
> instance MonadPlus m => MonadPlus (StateT s m) where
> mzero = StateT (const mzero)
> StateT st `mplus` StateT st' = StateT (\s -> st s `mplus` st' s)
> liftSt :: Monad m => m a -> StateT s m a
> liftSt m = StateT (\s -> m >>= \x -> return (x,s))
> callSt :: Monad m => StateT s m a -> s -> m a
> callSt (StateT st) s = st s >>= return . fst
> runSt :: St s a -> s -> a
> runSt st = runIdentity . callSt st
\end{verbatim}
In addition to the standard monad functions, state monads should
provide means to fetch and change the state. With multi-parameter type
classes, one could use the following class:
\begin{verbatim}
class Monad m => StateMonad s m where
update :: (s -> s) -> m s
fetch :: m s
change :: s -> m s
fetch = update id
change = update . const
instance Monad m => StateMonad s (StateT s m) where
update f = StateT (\s -> return (s,f s))
\end{verbatim}
Unfortunately multi-parameter type classes are not available in
Haskell~98. Therefore we define the corresponding instance functions
for each state monad class separately. Here are the functions for the
state transformers.
\begin{verbatim}
> updateSt :: Monad m => (s -> s) -> StateT s m s
> updateSt f = StateT (\s -> return (s,f s))
> updateSt_ :: Monad m => (s -> s) -> StateT s m ()
> updateSt_ f = StateT (\s -> return ((),f s))
> fetchSt :: Monad m => StateT s m s
> fetchSt = updateSt id
> changeSt :: Monad m => s -> StateT s m s
> changeSt = updateSt . const
\end{verbatim}
Currying and uncurrying for state monads has been implemented
in~\cite{Fokker95:JPEG}. Here we extend this implementation to the
parametric monad classes.
\begin{verbatim}
> stCurry :: Monad m => StateT (s,t) m a -> t -> StateT s m (t,a)
> stCurry (StateT st) t =
> StateT (\s -> st (s,t) >>= \(x,(s',t')) -> return ((t',x),s'))
> stUncurry :: Monad m => (t -> StateT s m (t,a)) -> StateT (s,t) m a
> stUncurry f =
> StateT (\(s,t) -> let (StateT st) = f t
> in st s >>= \((t',x),s') -> return (x,(s',t')))
\end{verbatim}
\subsection{Environment monad}
A variant of the state transformer monad is the environment monad
which is also known as (state) reader monad.
\begin{verbatim}
> data ReaderT r m a = ReaderT (r -> m a)
> type Rt r a = ReaderT r Identity a
> unReaderT :: ReaderT r m a -> (r -> m a)
> unReaderT (ReaderT rt) = rt
> instance Functor f => Functor (ReaderT r f) where
> fmap f (ReaderT rt) = ReaderT (fmap f . rt)
> instance Monad m => Monad (ReaderT r m) where
> return x = ReaderT (\_ -> return x)
> ReaderT rt >>= f = ReaderT (\r -> rt r >>= \x -> unReaderT (f x) r)
> fail msg = ReaderT (const (fail msg))
> instance MonadPlus m => MonadPlus (ReaderT r m) where
> mzero = ReaderT (\_ -> mzero)
> ReaderT rt `mplus` ReaderT rt' = ReaderT (\r -> rt r `mplus` rt' r)
> liftRt :: Monad m => m a -> ReaderT r m a
> liftRt m = ReaderT (\_ -> m)
> callRt :: ReaderT r m a -> r -> m a
> callRt (ReaderT rt) r = rt r
> runRt :: Rt r a -> r -> a
> runRt rt = runIdentity . callRt rt
> envRt :: Monad m => ReaderT r m r
> envRt = ReaderT return
\end{verbatim}
Currying can also be applied to state reader monads.
\begin{verbatim}
> rtCurry :: Monad m => ReaderT (r,t) m a -> t -> ReaderT r m a
> rtCurry (ReaderT rt) t = ReaderT (\r -> rt (r,t))
> rtUncurry :: Monad m => (t -> ReaderT r m a) -> ReaderT (r,t) m a
> rtUncurry f = ReaderT (\(r,t) -> let (ReaderT rt) = f t in rt r)
\end{verbatim}
A state reader transformer can be transformed trivially into a state
transformer monad. This is handled by the combinator \texttt{ro}.
\begin{verbatim}
ro :: Monad m => ReaderT r m a -> StateT r m a
ro (ReaderT rt) = StateT (\s -> rt s >>= \x -> return (x,s))
\end{verbatim}