This is very very informative, thanks.<div><br></div><div>One thing I still struggle with (because I haven&#39;t practiced much I guess) is writing down the desugaring/evaluation/expansion/reduction (how do you call it?). I know how to do it more or less (tried it for a fix fac, since fix feels like magic for an imperative programmer). This is unfortunate, because the claim that &quot;Haskell is easier to reason with&quot; together with &quot;controlling space/time&quot; only works I guess if you (1) developed an intuition about how the evaluation exactly works and/or (2) are trained in this algebraic rewriting (which I was 20 years ago ;-) If I do the rewriting, I often get it wrong (too lazy, too strict) and this it is rather useless. And many of the examples I&#39;ve seem seem to skim many &quot;obvious&quot; rewriting steps that don&#39;t feel that obvious to me.</div>
<div><br></div><div>But you gave a good exercise here :-)</div><div><br></div><div>This is typical for when I see Haskell code from experts: how do they make it so compact? Often the code is unreadable then, but in the case of your cleanup, I had to feeling &quot;why didn&#39;t write it like that in the first place? It seems so obvious&quot; ;-) This also has an intimidating effect sometimes, since as a newbie (and it feels that I&#39;m still a newbie after a year) it&#39;s hard to show code without looking like a fool. Luckily Haskell people are very friendly and helpful!</div>
<div><br></div><div><div><div class="gmail_quote">On Thu, Aug 20, 2009 at 10:18 AM, Ryan Ingram <span dir="ltr">&lt;<a href="mailto:ryani.spam@gmail.com">ryani.spam@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">On Wed, Aug 19, 2009 at 1:20 PM, Peter Verswyvelen&lt;<a href="mailto:bugfact@gmail.com">bugfact@gmail.com</a>&gt; wrote:<br>
&gt; Well I really wrote this code as an exercise, and it was a good one. Now I<br>
&gt; (or someone) needs to explain why it works.<br>
<br>
</div>There&#39;s a bit of trickiness, but it&#39;s not that hard when you break it down.<br>
<br>
Lets look at a simplified version of &quot;test&quot;:<br>
<br>
test = do<br>
    x &lt;- inp<br>
    out &quot;hello&quot;<br>
    out x<br>
    test<br>
<br>
Desugaring a bit:<br>
<br>
test<br>
= inp &gt;&gt;= \x -&gt; out hello &gt;&gt; out x &gt;&gt; test<br>
= S (\(i:is) -&gt; (is, empty, i))<br>
   &gt;&gt;= \x -&gt; S (\is -&gt; (is, singleton &quot;hello&quot;, ()))<br>
   &gt;&gt;= \_ -&gt; S (\is -&gt; (is, singleton x, ()))<br>
   &gt;&gt;= \_ -&gt; test<br>
<br>
Now, inlining &gt;&gt;= and simplifying, we get:<br>
<br>
test = S (\i0 -&gt; let<br>
           (i1, o1, x) = (\(i:is) -&gt; (is, empty, i)) i0<br>
           (i2, o2, _) = (i1, singleton &quot;hello&quot;, ())<br>
           (i3, o3, _) = (i2, singleton x, ())<br>
           (i4, o4, res) = step test i3<br>
           outputs = o1 `mappend` o2 `mappend` o3 `mappend` o4<br>
      in (i4, outputs, res))<br>
<br>
The first thing to notice is that when we run &quot;test&quot; by giving it some<br>
input, we *immediately* get a triple back:<br>
    (i4, outputs, res)<br>
with the values in the triple being unevaluated thunks.<br>
<br>
&quot;res&quot; is _|_; trying to evaluate it will infinite loop.  Similarily<br>
for i4.  But fortunately we never do; getOutput throws them both away.<br>
So the only thing we care about is &quot;outputs&quot;.<br>
<br>
outputs is infinite as well, but we have hope!  As long as `mappend`<br>
is lazy in its second argument, we might be able to get some data out!<br>
<br>
Lets simplify Data.DList a bit:<br>
<br>
mappend = (.)<br>
singleton = (:)<br>
empty = id<br>
fromList = (++)<br>
toList = ($ [])<br>
<br>
Now lets try to evaluate (toList outputs):<br>
<br>
toList outputs<br>
= ($ []) (o1 . o2 . o3 . o4)<br>
= o1 . o2 . o3 . o4 $ []<br>
= o1 (o2 (o3 (o4 [])))<br>
<br>
We need to evaluate o1 in order to call it.  There is a possibility<br>
that it is _|_ :<br>
    (i1, o1, x) = (\(i:is) -&gt; (is, empty, i)) i0<br>
<br>
Therefore<br>
   o1 = case i0 of<br>
       (i:is) -&gt; empty<br>
       [] -&gt; error &quot;pattern match failure&quot;<br>
    i1 = case i0 of<br>
       (i:is) -&gt; is<br>
       [] -&gt; error &quot;pattern match failure&quot;<br>
    x = case i0 of<br>
        (i:is) -&gt; i<br>
        [] -&gt; error &quot;pattern match failure&quot;<br>
<br>
So as long as you type a line, &quot;o1&quot; will be &quot;empty&quot; (= id).  But we<br>
don&#39;t know that you necessarily will type an input line, so the code<br>
*has* to wait for the line of input from the user, and can&#39;t print any<br>
later values.  (This is where you get into some of the craziness of<br>
lazy I/O)<br>
<br>
Once you type a line, i0 gets bound to (whatever you type : some lazy<br>
thunk representing the rest of the input) and o1 gets evaluated to id.<br>
<br>
toList outputs<br>
= o1 (o2 (o3 (o4 [])))<br>
= id (o2 (o3 (o4 [])))<br>
= o2 (o3 (o4 []))<br>
<br>
o2 and o3 are easy:<br>
           (i2, o2, _) = (i1, singleton &quot;hello&quot;, ())<br>
           (i3, o3, _) = (i2, singleton x, ())<br>
therefore<br>
    o2 = (&quot;hello&quot; :)<br>
    o3 = (x :)<br>
<br>
toList outputs<br>
= o2 (o3 (o4 []))<br>
= (&quot;hello&quot;:) ( (x:) (o4 []) )<br>
= &quot;hello&quot; : x : (o4 [])<br>
<br>
Now we have some data!  We can output these two elements without<br>
evaluating o4 at all!<br>
<br>
So we do, and then we need to evaluate o4.  But that just is starting<br>
over; o4 = getOutputs (step test i3).  We do have a different input<br>
(i3 vs. i0), but the rest of the logic is the same, and we keep going<br>
until we get to the end of the input list, at which point the pattern<br>
match failure in &quot;inp&quot; hits us.<br>
<div class="im"><br>
&gt; But is this monad really useful? I mean it would be straightforward to write<br>
&gt; this using the ST monad I guess?<br>
<br>
</div>It&#39;s kind of useful.  I don&#39;t think I&#39;d use ST, though.  It&#39;s isomorphic to<br>
StateT [String] (Writer (DList String))<br>
<div class="im"><br>
&gt; Anyway, the reason why I want this pure code is that even with a console<br>
&gt; based game, I don&#39;t want IO in it, since recording the input and replaying<br>
&gt; it is vital to reproduce the actions the user did, and if things go wrong<br>
&gt; (they always do), the log of all input can be used to restore the exact game<br>
&gt; play. Of course you can do the same using imperative techniques and IO<br>
&gt; redirection (which I did for my old games), but with this pure code you<br>
&gt; don&#39;t have to worry about other places where IO could be used.<br>
<br>
</div>For logging/testing/whatever, I suggest building your monad based off<br>
of MonadPrompt; it guarantees that all impure actions go through a<br>
datatype which you can then log.  Check it out!<br>
<a href="http://hackage.haskell.org/package/MonadPrompt" target="_blank">http://hackage.haskell.org/package/MonadPrompt</a><br>
<br>
You can then change the implementation of &quot;what does this impure<br>
action do&quot; without changing any of the logging or gameplay code.  For<br>
example, you could have a &quot;object agent monad&quot; which each character<br>
runs under, that is able to observe parts of the gamestate, and then<br>
write an interpreter that allows the user to play the game (through an<br>
impure I/O interface that draws to the screen) and another interpreter<br>
which runs an AI (through a pure functional or memory-state-based<br>
interface).<br>
<font color="#888888"><br>
  -- ryan<br>
</font></blockquote></div><br></div></div>