I want a State monad where fail modifies the state rather than throwing an exception. Failure early in such an action should also skip any later actions.
For example, the following should produce "FAILED: foo" as the final state:
execState (fail "foo") ""
this should produce the same result
execState (fail "foo" >> put "hi") ""
Using the standard State monad, the former throws an exception and the latter produces "hi"
I assume there’s some clever way to use StateT to make my own monad with this behavior, but haven’t figured it out yet. What’s a good way to accomplish this?
You can try using
StateTapplied toErrorT(though you may need the strict variant ofStateTto get your desired behaviour). Here, thefailcall gets thrown down the stack into the next monad.However, if you actually want it as part of the internal state rather than the stack, writing your own
State-like monad is probably the way to go, usingEitherinternally. For example, see how polyparse has a stateful parser with an internal datatype that records whether a failure has occurred or not.