<div>The insight is that the functions called can be lazy internally; the computation doesn&#39;t proceed by either fully evaluating something or not, but rather by rewriting parts of the computation graph.&nbsp; Here is a trace of the evaluation of &quot;prime&quot; for integers n &gt; 1:
</div>
<div>&nbsp;</div>
<div>prime n</div>
<div>=&gt; factors&nbsp;n == [1,n]</div>
<div>=&gt; factors n == 1 : n : [] -- remove syntactical sugar from the list</div>
<div>=&gt; [x | x &lt;- [1..n],&nbsp;n `mod` x == 0] == 1 : n : []</div>
<div>=&gt;*&nbsp;1 : [x | x &lt;-&nbsp;[2..n],&nbsp;n `mod` x == 0] == 1 : n : [] -- n mod 1 is always 0</div>
<div>=&gt; 1 == 1 &amp;&amp; [x | x &lt;- [2..n],&nbsp;n `mod` x == 0] ==&nbsp;n : []</div>
<div>=&gt; True &amp;&amp; [x | x &lt;- [2..n],&nbsp;n `mod` x == 0] ==&nbsp;n : []</div>
<div>=&gt; [x | x &lt;- [2..n],&nbsp;n `mod` x == 0] ==&nbsp;n : []</div>
<div>&nbsp;</div>
<div>This much computation happens for every single&nbsp;n.&nbsp;&nbsp;One of two things happens here; either we have another factor &lt; N, or we don&#39;t.</div>
<div>&nbsp;</div>
<div>Case 1: There is at least one other factor&nbsp;&lt; n.&nbsp; Let z be the smallest such factor:</div>
<div>=&gt;* z : [x | x &lt;- [(z+1)..n], n `mod` x == 0] == n : []</div>
<div>=&gt; z == n &amp;&amp; [x | x &lt;- [(z+1)..n], n `mod` x == 0] == []</div>
<div>=&gt; False &amp;&amp; [x | x &lt;- [(z+1)..n], n `mod` x == 0] == []</div>
<div>=&gt; False</div>
<div>&nbsp;</div>
<div>Case 2: There are no other factors &lt; n.</div>
<div>=&gt;* n : [x | x &lt;- [], n `mod` x == 0] == n : []</div>
<div>=&gt; n == n &amp;&amp; [x | x &lt;- [], n `mod` x == 0] == []</div>
<div>=&gt; True &amp;&amp; [x | x &lt;- [], n `mod` x == 0] == []</div>
<div>=&gt; [x | x &lt;- [], n `mod` x == 0] == []</div>
<div>=&gt; [] == []</div>
<div>=&gt; True</div>
<div>&nbsp;</div>
<div>Exercise: Annotate each line in the above trace with a description of why the reduction is valid.</div>
<div>&nbsp;</div>
<div>To be totally clear with this trace, you would need to desguar the list comprehension and some of the more primitive functions.&nbsp; The lines marked with =&gt;* are a bit handwavy because they skip evaluation.&nbsp; Here&#39;s the desugaring of this list comprehension and full definitions of the other functions in used in this example:
</div>
<div>&nbsp;</div>
<div>[x | x &lt;- [1..n],&nbsp;n `mod` x == 0] =&gt;</div>
<div>&nbsp;&nbsp;concatMap ok [1..n]</div>
<div>&nbsp;&nbsp;&nbsp; where&nbsp;ok x = if n `mod` x == 0 then [x] else []</div>
<div>&nbsp;</div>
<div>concatMap :: (a -&gt; [b]) -&gt; [a] -&gt; [b]</div>
<div>concatMap f [] = []</div>
<div>concatMap f (x:xs) = f x ++ concatMap f xs</div>
<div>&nbsp;</div>
<div>
<div>(++) :: [a] -&gt; [a] -&gt; [a]</div>
<div>
<div>(x:xs) ++ ys = x : (xs ++ ys)</div>[] ++ ys = ys</div>
<div>&nbsp;</div>(&amp;&amp;) :: Bool -&gt; Bool -&gt; Bool</div>
<div>True &amp;&amp; x = x</div>
<div>False &amp;&amp; _ = False</div>
<div>&nbsp;</div>
<div>(==) :: [Int] -&gt; [Int] -&gt; Bool -- specialized via typeclass &quot;Eq [Int]&quot;</div>
<div>(x:xs) == (y:ys) = x == y &amp;&amp; xs == ys</div>
<div>[] == [] = True</div>
<div>_ == _ = False</div>
<div>&nbsp;</div>
<div>All other functions used are primitives.</div>
<div>&nbsp;</div>
<div>Exercise: Write out a full execution&nbsp;trace for n ==&nbsp;3 and n == 4 with the desugaring and&nbsp;Prelude functions given&nbsp;above.</div>
<div>&nbsp;</div>
<div><span class="gmail_quote">On 8/22/07, <b class="gmail_sendername">Xavier Noria</b> &lt;<a href="mailto:fxn@hashref.com">fxn@hashref.com</a>&gt; wrote:</span>
<blockquote class="gmail_quote" style="PADDING-LEFT: 1ex; MARGIN: 0px 0px 0px 0.8ex; BORDER-LEFT: #ccc 1px solid">I am learning Haskell with &quot;Programming in Haskell&quot; (an excellent<br>book BTW).<br><br>I have background in several languages but none of them has lazy
<br>evaluation. By now I am getting along with the intuitive idea that<br>things are not evaluated until needed, but there&#39;s an example I don&#39;t<br>understand (which means the intuitive idea needs some revision :-).
<br><br>We have factors(), defined on page 39 like this[*]:<br><br>&nbsp;&nbsp;factors :: Int -&gt; [Int]<br>&nbsp;&nbsp;factors n = [x | x &lt;- [1..n], n `mod` x == 0]<br><br>and we base prime() on it this way:<br><br>&nbsp;&nbsp;prime :: Int -&gt; Bool
<br>&nbsp;&nbsp;prime n = factors n == [1, n]<br><br>Now, the books says prime does not necessarily compute all of the<br>factors of n because of lazy evaluation. Meaning that if n is<br>composite as soon as some non-trivial divisor appears we halt
<br>computation and return False.<br><br>My vague intuition said &quot;we either need factors or we don&#39;t, we do<br>because we need to perform the test, so we compute it&quot;. That&#39;s wrong,<br>so a posteriori the explanation must be something like this:
<br><br>1. someone knows we want factor() to perform an equality test<br><br>2. someone knows an equality test between lists is False as soon as<br>we have a mismatch, left to right<br><br>3. thus, instead of evaluating factors completely we are going to
<br>build sublists of the result and perform the tests on those ones<br>against [1, n].<br><br>That&#39;s a lot of *context* about that particular evaluation of<br>factors, in particular step puzzles me. Can anyone explain how lazy
<br>evaluation fits there? I suspect the key is the implementation of ==<br>together with the fact that list comprehensions are lazy themselves,<br>is that right?<br><br>-- fxn<br><br>[*] Which notation do you use for functions in text? is f() ok?
<br><br>_______________________________________________<br>Haskell-Cafe mailing list<br><a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br><a href="http://www.haskell.org/mailman/listinfo/haskell-cafe">
http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br></blockquote></div><br>