I try to make a derived instance for MonadWriter of the Continuation Monad Transformer. This is how i tried it:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
import Control.Monad.Cont
import Control.Monad.Writer
instance (MonadWriter w m) => MonadWriter w (ContT r m) where
tell= lift . tell
listen m= ContT $ \ c -> do
(a,w) <- listen $ runContT m (c)
return (a,w)
pass m = undefined
This gives me the following error:
Occurs check: cannot construct the infinite type: r = (r, w1)
When generalising the type(s) for `listen'
In the instance declaration for `MonadWriter w (ContT r m)'
Next try was this:
instance (MonadWriter w m) => MonadWriter w (ContT r m) where
tell= lift . tell
listen m= ContT $ \ c -> do
(a,w) <- runContT m (listen . c)
return (a,w)
pass m = undefined
Followed by:
Occurs check: cannot construct the infinite type: a = (a, w)
When generalising the type(s) for `listen'
In the instance declaration for `MonadWriter w (ContT r m)'
Does anyone know how to implement listen and pass here? Is there a reason why there is no instance declaration for this in the mtl? Please help me to understand this!
Regards Marian
PS: I've found that Blog Entry at blog.sigfpe.com where somewhere at the end of the discussion Edward Kmett says:
"(...) As I recall, 'pass' and 'local' cause problems with the current MTL when you start mixing in ContT, and should probably be factored into separate classes."
Maybe the same hold's also for listen from MonadWriter. So the simplest solution is, if you dont need listen and pass in a special case, to leave them undefined:
instance (MonadWriter w m) => MonadWriter w (ContT r m) where
tell= lift . tell
listen = undefined
pass = undefined
PS: (2011-03-11) Diving further in this subject I've come up with this solution: (When specifiying the type r on ContT as () we could try this:)
instance (MonadWriter w m) => MonadWriter w (ContT () m) where
listen m = do
a <- m
(_,w) <- lift $ listen $ runContT m (return . (const ()))
return (a,w)
This compiles! And runs! But, alas, the monadic action must be computed twice. May anybody take this as hint to collapse the two calls somehow into one? Then we will get the desired implementation.