Combining distinct-thread state monads?

Mark Carroll mark at
Fri Jan 9 10:12:43 EST 2004

Another bit of code that seems to work is:

convertState :: (s1 -> s2)
	     -> (s2 -> s1)
	     -> State s2 a
	     -> State s1 a

convertState fromState toState computation =
    do oldState <- get
       let (result, newState) =
	       runState computation (fromState oldState)
       put (toState newState)
       return result

Buoyed by this apparent success, I had a go with a Parsec parser:

convertParser :: (s1 -> s2)
	      -> (s2 -> s1)
	      -> GenParser tok s2 a
	      -> GenParser tok s1 a

convertParser fromState toState parser =
    do oldState <- getState
       oldInput <- getInput
       case runParser (wrapParser parser)
		(fromState oldState) "" oldInput of
              Left error ->
		  fail (show error)
              Right (result, newState, newInput) ->
		  do setState (toState newState)
                     setInput newInput
		     return result
    wrapParser parser =
	do result <- parser
	   state <- getState
	   input <- getInput
	   return (result, state, input)

However, this has problems, not least of which are that the source
filepath is lost in the handing down, and the ParseError can't be passed
upward easily without some extra housekeeping, so the resulting shown
error has multiple locations. So maybe composed monads are the way to go.

Is there a better way to do this - with lifting or whatever - *while
keeping the type signatures the same*? (If this has already been said in a
way that wasn't obvious to me the first time, just let me know who said it
and I'll hunt in the list archives.)

-- Mark

More information about the Haskell-Cafe mailing list