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
1 Answer 1
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.
2 Comments
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.Explore related questions
See similar questions with these tags.
ReaderT,WriterTandStateT. 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 useliftonce - 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...ain therunRWST :: r -> s -> m (a, s, w).m