[Haskell] State, StateT and lifting

Andrew Pimlott andrew at pimlott.net
Fri Mar 18 19:09:50 EST 2005


[I think it is preferred to post this on haskell-cafe.]

On Fri, Mar 18, 2005 at 02:00:37PM -0800, Juan Carlos Arevalo Baeza wrote:
> matchRuleST :: String -> State RuleSet (Maybe Rule)
> makeST :: String -> StateT RuleSet IO ()
> 
>   matchRuleST doesn't really need IO for anything (it just works on the 
> current state "RuleSet"). makeST needs IO (it does file date 
> comparisons, actions on the files, etc... the usual "make" stuff). The 
> problem is how to properly use matchRuleST from makeST.

You might solve this by changing the type of matchRuleST:

    matchRuleST :: MonadState RuleSet m => String -> m (maybe Rule)

(This requires -fglasgow-exts, but I don't think there's anything
controversial about non-variables in class constraints.)

>   Then, I decided to try again, and came up with this function:
> 
> liftState :: State s a -> StateT s m a

(I think you left out the constraint (Monad m).)

> liftState s = do
>    state1 <- get
>    (
>        let (result, state) = evalState (do {result <- s; state <- get; 
> return (result, state)}) state1 in do
>            put state
>            return result
>        )

You can turn this into a one-liner if you work on it a bit.  But I would
go with the above.

Aside:  It bugs me that this is not defined by Control.Monad.State
(alongside modify and gets):

    state :: MonadState s m => (s -> (a, s)) -> m a

I almost always end up defining it myself and use it to implement other
state transformers.  I would do the same for other monad classes
(Writer, etc): provide a function that captures the general operation.

Andrew


More information about the Haskell mailing list