I implemented a simple state machine in Python:
import time
def a():
print \"a()\"
return b
def b():
print \"b()\"
return c
def c():
print
If you use newtype
instead of data
, you don't incur any overhead. Also, you can wrap each state's function at the point of definition, so the expressions that use them don't have to:
import Control.Monad
newtype State = State { runState :: IO State }
a :: State
a = State $ print "a()" >> return b
b :: State
b = State $ print "b()" >> return c
c :: State
c = State $ print "c()" >> return a
runMachine :: State -> IO ()
runMachine s = runMachine =<< runState s
main = runMachine a
Edit: it struck me that runMachine
has a more general form; a monadic version of iterate
:
iterateM :: Monad m => (a -> m a) -> a -> m [a]
iterateM f a = do { b <- f a
; as <- iterateM f b
; return (a:as)
}
main = iterateM runState a
Edit: Hmm, iterateM
causes a space-leak. Maybe iterateM_
would be better.
iterateM_ :: Monad m => (a -> m a) -> a -> m ()
iterateM_ f a = f a >>= iterateM_ f
main = iterateM_ runState a
Edit: If you want to thread some state through the state machine, you can use the same definition for State
, but change the state functions to:
a :: Int -> State
a i = State $ do{ print $ "a(" ++ show i ++ ")"
; return $ b (i+1)
}
b :: Int -> State
b i = State $ do{ print $ "b(" ++ show i ++ ")"
; return $ c (i+1)
}
c :: Int -> State
c i = State $ do{ print $ "c(" ++ show i ++ ")"
; return $ a (i+1)
}
main = iterateM_ runState $ a 1