Ignat Insarov
Ignat Insarov

Reputation: 4832

Given a Nothing, how do I construct values of type RWST env log state Maybe value?

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

Answers (1)

luqui
luqui

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

Related Questions