Reputation: 4832
Suppose I want a computation that evaluates expressions with variables. I would like it to look variables up in the env passed to its runner, and also have some kind of state and a log. I take an algebra, pepper it with RWS
and I'm done.
Except that lookup
returns Maybe
.
So I need a monad stack.
λ type EvalA = MaybeT (RWS () () ()) ()
λ runRWS (runMaybeT (MaybeT (return (Just ())) :: EvalA )) () ()
(Just (),(),())
λ runRWS (runMaybeT (MaybeT (return Nothing) :: EvalA )) () ()
(Nothing,(),())
So far so good. But the type is somewhat messy: a transformer on top of a transformer on top of Identity
. Why not flip this.
λ type EvalB = RWST () () () Maybe ()
λ runRWST (return () :: EvalB) () ()
Just ((),(),())
λ runRWST (Nothing :: EvalB) () ()
<interactive>:12:10: error:
• Couldn't match type ‘Maybe a0’ with ‘RWST () () () Maybe ()’
Expected type: EvalB
Actual type: Maybe a0
..........
λ -- ...?
Putting aside that having a Nothing
plus a log is better than having a Nothing
alone, how can I obtain a Nothing
from EvalB
?
Upvotes: 1
Views: 85
Reputation: 60503
You need to lift
, which is the fundamental operation monad transformers support.
ghci> runRWST (lift Nothing) () ()
Nothing
But also be careful doing this kind of swapping. Maybe
does not commute with RWS
. In fact, it doesn't commute with any of them! For example:
WriterT w Maybe a
≃ Maybe (a, w)
but
MaybeT (Writer w a)
≃ Writer w (Maybe a)
≃ (Maybe a, w)
In the former, with Maybe
as the base monad, a Nothing
value erases the writer's log -- all you get is failure. In the latter, with Writer
as the base, the computation can fail yet still produce a value in the log.
A very good exercise is to do this with each of Reader
, Writer
, and State
, and find a computation that is representable in one of MaybeT m
, mT Maybe
but not the other.
Upvotes: 3