1

I have looked at this to try to understand how several transformer monads interact, and especially getting a better understanding of lift and stacking with monads.

For the RWST monad found here (I think this is the best documentation of it), is it the case that it is a stacked monad where the Reader, Writer, State each are a monadic layer (and in that order of stacking). Or how is it supposed to be understood? When I look at the definition runRWST :: r -> s -> m (a, s, w) I understand it as taking reader-environment a state-environment and wrapping any monad m around the return value of RWS. This also means that there only exists two layers of monads in this monad. That is, the outer monad m , and a tuple containing several monads.

This in turn also means that you can only use the lift once. Lifting a value from either the reader or the state monad into the outer monad.

In that sense get and ask are just two functions applying one of either two of the inner monads. For this last point I am still not sure I understand why you would need both a reader a state-monad even having read this stackoverflow post. The reader is only meaningfull for read-only I guess, but if one didn't want that, could one use a transformer monad around two seperat state-monads?

An example:

The comments have given me reason to ponder and make the following more explicit.... Of the following type definition what what would be the inner monad, and the outer monad? Is the RWST itself a Monad wrapped around (and therefor an outer monad) Either String (the inner monad) ?

type MyRWST a = RWST
 (String -> Either String MyType) 
 [Int] 
 (MyEnv, [String], [String])
 (Either String)
 a
asked Oct 9, 2023 at 12:21
7
  • 2
    It is equivalent to a stack of ReaderT, WriterT and StateT. Whether you look at it as a single transformer or all three or just two is a matter of interpretation, but at any rate the type system treats it as a single transformer, therefore you'd only use lift once - but this does not lift values from either reader or state or writer into the RWST monad, but from the underlying monad (e.g. IO). - - I'm struggling to understand what actually your question is... Commented Oct 9, 2023 at 12:34
  • 1
    RWST is not a monad stack, it is a single monad that implements multiple functionalities (reader, writer, state). Commented Oct 9, 2023 at 12:35
  • @leftaroundabout what do you mean by "but from the underlying monad" is that the a in the runRWST :: r -> s -> m (a, s, w). Commented Oct 9, 2023 at 12:38
  • @JoachimBreitner are you then disagreeing with leftaroundabout ? Commented Oct 9, 2023 at 12:38
  • @Piskator no, it's m Commented Oct 9, 2023 at 12:41

1 Answer 1

9

The inner monad of a monad transformer is always a type parameter. The type you've provided isn't a transformer.

type MyRWST a = RWST
 (String -> Either String MyType) 
 [Int] 
 (MyEnv, [String], [String])
 (Either String)
 a

This is a Monad. Compare this to a transformer like MaybeT.

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

MaybeT takes two type parameters, and the first itself takes a parameter, so its kind is (* -> *) -> * -> *. With more explicit parentheses, that's (* -> *) -> (* -> *). And now we can see why it's called a transformer. It takes one monad (of kind * -> *) and transforms it into a new monad (also of kind * -> *).

RWST is defined as

newtype RWST r w s m a = RWST { unRWST :: r -> s -> w -> m (a, s, w) }

Now this takes a lot of type arguments, but if we fix r, w, and s, we get a transformer. That is, RWST is not, itself, a monad transformer, but for any r, w, and s, RWST r w s is a transformer. The full kind of RWST is

RWST :: * -> * -> * -> (* -> *) -> * -> *

And while you can think of RWST as having three layers (reader, writer, and state), it really only does have one. The "next layer down" of RWST r w s m is really m. So to directly answer your question about lift, the type signature of lift is

lift :: (MonadTrans t, Monad m) => m a -> t m a

and when t ~ RWST r w s, we get

lift :: Monad m => m a -> RWST r w s m a

So a single lift takes us over the whole RWST r w s mess.

answered Oct 9, 2023 at 12:56
Sign up to request clarification or add additional context in comments.

2 Comments

@leftaroundabout and Silvio Mayolo ,yes the one I originally stated does compile the way it was written.
@leftaroundabout Ah, thank you! I was reading the MyRWST declaration as a data not a type, so I thought OP's RWST was a data constructor of their own defining. I see the issue now. Edited the post.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.