[Haskell-cafe] Re: [Haskell] State, StateT and lifting

Juan Carlos Arevalo Baeza jcab.lists at JCABs-Rumblings.com
Sat Mar 19 06:25:32 EST 2005


Andrew Pimlott wrote:

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

   Oops! I guess you're right.

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

   I don't know... The original using IO somehow offended me because it 
was not an operation that required IO. This one leaves the inner monad 
unspecified, but still looks like baggage to me.

>>  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).)
>  
>

   Yes, I did, thanx. I wrote the message a tad little bit too early :-P

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

   Yes. I prefer clarity, too. And I did it ugly (still groping with the 
syntax). This is the final version:

liftState :: Monad m => State s a -> StateT s m a
liftState s = do
    state1 <- get
    let (result, state) = evalState (do {result <- s; state <- get; 
return (result, state)}) state1
    put state
    return result

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

   Cute, thanx! It's good to know I wasn't just missing something 
obvious. So, this is my final implementation (works!):

state :: MonadState s m => (s -> (a, s)) -> m a
state sm = do
    s <- get
    let (result, newState) = sm s
    put newState
    return result

liftState :: Monad m => State s a -> StateT s m a
liftState (State f) = state f

JCAB



More information about the Haskell-Cafe mailing list