I try to make a derived instance for MonadWriter of the Continuation Monad Transformer. This is how i tried it:
{-# LANGUAGE MultiParamTypeClasses, FlexibleI
I don't think it's possible. For reference, here's the meaning of ContT
:
ContT r m a = (a -> m r) -> m r
Here's my starting point for listen
:
listen m = ContT $ \c ->
runCont m (\x -> c (x,w))
The question is, where do we get w
? w
will come from the computation that runCont m
performs before it calls our function \x -> c (x,w)
with its return value x
. That is, the information we need to pass to c
comes from runCont
, so we would need to do something like this:
listen m = ContT $ \c -> do
rec (r,w) <- listen . runContT m $ \x -> c (x,w)
return r
(Needs LANGUAGE DoRec
and MonadFix m
in the context)
Although that typechecks, it is not correct. w
is now the value written by the entire computation, not just the portion before calling our continuation \x -> c (x,w)
.
Do you see what you would need to do? I know my answer is essentially "I think it's impossible because I can't think of a way to do it" (what Conal Elliott calls "proof by lack of imagination"), but I think my lack of imagination is correct this time. The information we need is destroyed before we have a chance to peek at it.
I believe this instance is possible with the Codensity monad transformer:
newtype CodensityT m a = CodensityT { runCodensityT :: forall r. (a -> m r) -> m r }
which gives you the same performance improvements as Cont
in the cases where it does that, but doesn't support callCC
. This is because you can runCodensityT
in the middle of a computation with whatever r
you want.
listen m = CodensityT $ \c -> listen (runCodensityT m return) >>= c
Maybe callCC
is the problem. I wouldn't be surprised if you could come up with an example combining listen
and callCC
that would create a paradox.