(note: followup set to haskell-cafe)
Hi,
As you have suggested me last time, I've studied the 2 papers from
Mark P. Jones about Monad composition, and I've found his framework
(as explained in "Functional Programming with Overloading and
Higher-Order Polymorphism") very neat compared to the one I had in
mind.
However it seam to me it is less powerful also: the problem is that I
couldn't find any way to define monad operations that take a Monad
Transformer as argument.
I'll make an example based on the paper cited above: here is a Monad
Transformer class with its lift function.
\begin{code}
class (Monad m, Monad (t m)) => MonadT t m where
lift :: m a -> t m a
\end{code}
Now I define a Reader Monad Transformer
\begin{code}
class (Monad m) => MonadReader m s where
ask :: m s
local :: (s -> s) -> m a -> m a
newtype ReaderT s m a = ReaderT { runReaderT :: s -> m a }
instance (Functor m) => Functor (ReaderT s m) where
fmap f t = ReaderT (\s -> fmap f (runReaderT t s))
instance (Monad m) => Monad (ReaderT s m) where
return x = ReaderT (\s -> return x)
t >>= k = ReaderT (\s -> do m <- runReaderT t s
runReaderT (k m) s)
instance (Monad m) => MonadT (ReaderT s) m where
lift m = ReaderT (\s -> do { x <- m ; runReaderT (return x) s })
\end{code}
And a simple Identity monad used to "plug" the final "hole"
\begin{code}
newtype Id a = Id { runId :: a }
instance Functor Id where
fmap f (Id x) = Id (f x)
instance Monad Id where
return x = Id x
m >>= k = k (runId m)
test :: a -> ReaderT s (ReaderT t Id) a
test x = return x
\end{code}
Now, as noted in the paper, I can define the monad operation "ask"
1) for all Monad applied to ReaderT, and
2) for all MonadReader applied to any Monad Transformer
Thus "ask" is defined for all possible compositions of the
MonadReader.
However I can't define "local" in the same way; the problem is the
second type of instance declaration: "local" need a MonadReader as its
second argument, an this MonadReader in the instance declaration is
the composition of a MonadTransformer t and a MonadReader m, thus I
need some other MonadT operation beside lift to implement the new
"local" in term of the m's one.
\begin{code}
instance (Monad m) => MonadReader (ReaderT s m) s where
ask = ReaderT (\s -> return s)
local f t = ReaderT (\s -> runReaderT t (f s))
instance (MonadT t m, MonadReader m s, Monad (t m)) => MonadReader (t m) s where
ask = lift (ask)
-- local??
\end{code}
Moreover, Monad operations that discard the Monad (such as runST,
runReader, catch, etc.) pose an even more difficult problem: how can
you define these operations for all possible composition of the Monad
Transformer?
I can easily define them for all monad applied to the monad
transformer, but not the other way around. In example, I may desire a
class like this
\begin{code}
class (MonadT t m, Monad m, MonadReader (t m) s) => MonadReaderRun t m s where
runReader :: t m a -> s -> m a
\end{code}
The first type of instance declaration for ReaderT is easily
defined...
\begin{code}
instance (Monad m) => MonadReaderRun (ReaderT s) m s where
runReader = runReaderT
\end{code}
...But obviously I cannot make an instance declaration for all
MonadReaderRun applied to any Monad Transformer.
I'm missing something?
Thanks in advance,
--
Diego Dainese