
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 where 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