[Haskell-cafe] Stacking State on State.....
Daniel Fischer
daniel.is.fischer at web.de
Sat Feb 28 10:08:19 EST 2009
Am Samstag, 28. Februar 2009 15:36 schrieb Andrew Wagner:
> Ok, so this question of stacking state on top of state has come up several
> times lately. So I decided to whip up a small example. So here's a goofy
> little example of an abstract representation of a computer that can compute
> a value of type 'a'. The two states here are a value of type 'a', and a
> stack of functions of type (a->a) which can be applied to that value.
Nice.
> Disclaimer: this code is only type-checked, not tested!
>
> import Control.Monad.State
import Control.Moand (unless)
>
> -- first, we'll rename the type, for convenience
> type Programmable a = StateT [a->a] (State a)
>
> -- add a function to the stack of functions that can be applied
> -- notice that we just use the normal State functions when dealing
> -- with the first type of state
> add :: (a -> a) -> Programmable a ()
> add f = modify (f:)
>
> -- add a bunch of functions to the stack
> -- this time, notice that Programmable a is just a monad
> addAll :: [a -> a] -> Programmable a ()
> addAll = mapM_ add
Be aware that this adds the functions in reverse order, an alternative is
addAll = modify . (++)
(addAll fs = modify (fs ++))
>
> -- this applies a function directly to the stored state, bypassing the
> function stack
> -- notice that, to use State functions on the second type of state, we must
> use
> -- lift to get to that layer
> modify' :: (a -> a) -> Programmable a ()
> modify' f = lift (modify f)
>
> -- pop one function off the stack and apply it
> -- notice again the difference between modify' and modify. we use modify'
> to modify the value
> -- and modify to modify the function stack. This is again because of the
> order in which we wrapped
> -- the two states. If we were dealing with StateT a (State [a->a]), it
> would be the opposite.
> step :: Programmable a ()
> step = do
> fs <- get
> let f = if (null fs) then id else (head fs)
> modify' f
> modify $ if (null fs) then id else (const (tail fs))
Last line could be
modify (drop 1)
>
> -- run the whole 'program'
> runAll :: Programmable a ()
> runAll = do
> fs <- get
> if (null fs) then (return ()) else (step >> runAll)
runAll = do
stop <- gets null
unless stop (step >> runAll)
More information about the Haskell-Cafe
mailing list