I have a RWST in haskell over a Maybe, which short circuits under certain conditions. I want to run this action until it returns Nothing, and get the last Just. So my situation is as follows;
type St = MyState
type Re = MyRead
type Wr = MyWriter
type Foo = RWST Re Wr St Maybe
action :: Foo ()
The only way that I thought of for achieving that, is by defining the following;
run = action >> run <|> action
which has the downside that if the short circuiting happens on the first second run, even though there is an output, I get Nothing because run
runs the action twice. Is there any better way of looping? I looked into extra
but the functions supplied there do not help my cause.
So, after considering the answers given, and trying everything out, it seems the easiest solution is to use many
. In the general case though, swapping for a MaybeT as suggested is a better solution.
I've been looking over your question and going back and forth about whether this answer applies to your situation. Really I can't tell without more context, so I'll just leave it here in case.
You are using Maybe
as the base monad, and that might not be what you want. I want to forget about the reader and writer part of RWST
for a moment and pretend we are just using StateT
, because it simpler, but the same idea applies (StateT
is basically the same thing as RWST () ()
after all). The definition of StateT
is:
newtype StateT s m a = StateT (s -> m (a, s))
So, after all is unrolled and done, the type of run
ends up as
run :: St -> Maybe ((), St)
You give it an St
, and it gives you back either a pair with a resulting St
in it, or Nothing
. In particular, when it "fails" (as in, returns Nothing
), the failure does not come with a resulting state, so all state changes prior to the failure are forgotten. That means if you ever take the right side of (<|>)
, anything that happened in the left side doesn't matter anymore, the only influence it has on the result is the fact that it failed. But the fact that you want to do this in a loop betrays that you want to keep the state changes after failure.
That is what MaybeT
is for. Put the MaybeT
on the outside. MaybeT
is defined as
newtype MaybeT m a = MaybeT (m (Maybe a))
So if your monad were MaybeT (State St)
, the implementation type would be
run :: St -> (Maybe (), St)
Notice that now, whether the action succeeds or fails, we get an St
out the other end. This will allow (<|>)
to carry on manipulating the state that its left side changed rather than starting anew, which I'm guessing is your intention (though I can't say for sure).
In general, the inner monads of a transformer chain are more powerful -- a transformer are always subject to the rules of their inner monad. The "primary" effect of StateT s Maybe
is that it either succeeds with a value or fails outright, and then the statefulness has to be "emulated" on top of that. Whereas the primary effect of MaybeT (State s)
is that of statefulness -- no matter what MaybeT
does, there is always a single state carried through the computation. More on transformer stack design here.