Heh. Actually, there is no more rewrite. But I muffed the second definition: it should, of course be:<br><br>type Programmable a = State2 [a->a] a<br><br><div class="gmail_quote">On Sat, Feb 28, 2009 at 10:35 AM, Andrew Wagner <span dir="ltr"><<a href="mailto:wagner.andrew@gmail.com" target="_blank">wagner.andrew@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Thanks for helping clean up my dirty little hacking. This could actually be made nicer by defining the following, and rewriting the original code in terms of it:<br>
<br>
type State2 a b = StateT a (State b)<br>
type Programmable a = State2 a (a->a)<br>
<br>
I'll leave the rewrite as an exercise for the reader, since I'm standing in the store writing this on my iPhone :)<div><div></div><div><br>
<br>
<br>
On Feb 28, 2009, at 10:08 AM, Daniel Fischer <<a href="mailto:daniel.is.fischer@web.de" target="_blank">daniel.is.fischer@web.de</a>> wrote:<br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Am Samstag, 28. Februar 2009 15:36 schrieb Andrew Wagner:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Ok, so this question of stacking state on top of state has come up several<br>
times lately. So I decided to whip up a small example. So here's a goofy<br>
little example of an abstract representation of a computer that can compute<br>
a value of type 'a'. The two states here are a value of type 'a', and a<br>
stack of functions of type (a->a) which can be applied to that value.<br>
</blockquote>
<br>
Nice.<br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Disclaimer: this code is only type-checked, not tested!<br>
<br>
import Control.Monad.State<br>
</blockquote>
<br>
import Control.Moand (unless)<br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
-- first, we'll rename the type, for convenience<br>
type Programmable a = StateT [a->a] (State a)<br>
<br>
-- add a function to the stack of functions that can be applied<br>
-- notice that we just use the normal State functions when dealing<br>
-- with the first type of state<br>
add :: (a -> a) -> Programmable a ()<br>
add f = modify (f:)<br>
<br>
-- add a bunch of functions to the stack<br>
-- this time, notice that Programmable a is just a monad<br>
addAll :: [a -> a] -> Programmable a ()<br>
addAll = mapM_ add<br>
</blockquote>
<br>
Be aware that this adds the functions in reverse order, an alternative is<br>
<br>
addAll = modify . (++)<br>
<br>
(addAll fs = modify (fs ++))<br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
-- this applies a function directly to the stored state, bypassing the<br>
function stack<br>
-- notice that, to use State functions on the second type of state, we must<br>
use<br>
-- lift to get to that layer<br>
modify' :: (a -> a) -> Programmable a ()<br>
modify' f = lift (modify f)<br>
<br>
-- pop one function off the stack and apply it<br>
-- notice again the difference between modify' and modify. we use modify'<br>
to modify the value<br>
-- and modify to modify the function stack. This is again because of the<br>
order in which we wrapped<br>
-- the two states. If we were dealing with StateT a (State [a->a]), it<br>
would be the opposite.<br>
step :: Programmable a ()<br>
step = do<br>
fs <- get<br>
let f = if (null fs) then id else (head fs)<br>
modify' f<br>
modify $ if (null fs) then id else (const (tail fs))<br>
</blockquote>
<br>
Last line could be<br>
<br>
modify (drop 1)<br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
-- run the whole 'program'<br>
runAll :: Programmable a ()<br>
runAll = do<br>
fs <- get<br>
if (null fs) then (return ()) else (step >> runAll)<br>
</blockquote>
<br>
runAll = do<br>
stop <- gets null<br>
unless stop (step >> runAll)<br>
<br>
<br>
</blockquote>
</div></div></blockquote></div><br>