[Haskell-cafe] State separation/combination pattern question

Ian Lynagh igloo at earth.li
Wed Jan 3 17:07:15 EST 2007


Hi Reto,

On Thu, Dec 21, 2006 at 10:11:22PM -0800, Reto Kramer wrote:
> 
> I've tried to thread the two states (StateA and StateB) using a chain  
> of StateT ... StateT ..., but couldn't really make that work.

That is how I would write it; I have attached code for your example.

> It  
> seems rather arbitrary in this case which state to make the inner/ 
> outer one

The choice is indeed arbitrary.

> and depending on this ordering the "lifts" have to go with  
> one or the other set of store calls.

If you don't mind turning on overlapping and undecidable instances then
you don't need to manually lift things at all.


Thanks
Ian

-------------- next part --------------

{-# OPTIONS_GHC -fglasgow-exts
                -fallow-overlapping-instances
                -fallow-undecidable-instances #-}

import Control.Monad.Trans (MonadTrans) 
import Control.Monad.State (StateT, evalStateT, get, put, lift)

-- StateA

type StateA = [Integer]                                                         

newtype MonadAT m a = MonadAT (StateT StateA m a)
    deriving (Monad, MonadTrans)

class Monad m => MonadA m where
    getA :: m StateA
    putA :: StateA -> m ()

instance Monad m => MonadA (MonadAT m) where
    getA = MonadAT get
    putA = MonadAT . put

instance (MonadTrans t, MonadA m, Monad (t m)) => MonadA (t m) where
    getA = lift getA
    putA = lift . putA

evalAT :: Monad m => MonadAT m a -> StateA -> m a
evalAT (MonadAT x) = evalStateT x

-- StateB

type StateB = [Integer]                                                         

newtype MonadBT m a = MonadBT (StateT StateB m a)
    deriving (Monad, MonadTrans)

class Monad m => MonadB m where
    getB :: m StateB
    putB :: StateB -> m ()

instance Monad m => MonadB (MonadBT m) where
    getB = MonadBT get
    putB = MonadBT . put

instance (MonadTrans t, MonadB m, Monad (t m)) => MonadB (t m) where
    getB = lift getB
    putB = lift . putB

evalBT :: Monad m => MonadBT m a -> StateB -> m a
evalBT (MonadBT x) = evalStateT x

-- The program

type Monads = MonadBT (MonadAT IO)

main :: IO ()
main = do res <- evalAT (evalBT exec []) []
          print res

exec :: Monads (StateA, StateB)
exec = do foo
          bar
          foo
          foo
          bar
          a <- getA
          b <- getB
          return (a, b)

foo :: MonadA m => m ()
foo = do st <- getA
         putA (1 : st)

bar :: MonadB m => m ()
bar = do st <- getB
         putB (2 : st)



More information about the Haskell-Cafe mailing list