<table cellspacing="0" cellpadding="0" border="0" ><tr><td valign="top" style="font: inherit;">OK, I think I understand. You were explaining how ML could be made to emulate Haskell laziness using streams, ala Scheme type delayed evaluation, so it's kind of like you were explaining a question I hadn't quite asked yet, which maybe explains my puzzlement, I hope.<br><br>Also, though my understanding of both Haskell and ML syntax is still rudimentary, I did catch an error in your definition of chain_take: the first arg of the cons should be i rather than n.<br><br>I'm still going through your code and may have further questions.<br><br>Thanks for your input.<br><br>Michael<br><br><br>--- On <b>Wed, 5/20/09, Ryan Ingram <i>&lt;ryani.spam@gmail.com&gt;</i></b> wrote:<br><blockquote style="border-left: 2px solid rgb(16, 16, 255); margin-left: 5px; padding-left: 5px;"><br>From: Ryan Ingram &lt;ryani.spam@gmail.com&gt;<br>Subject: Re: [Haskell-cafe] showing a
 user defined type<br>To: "michael rice" &lt;nowgate@yahoo.com&gt;<br>Cc: "Brandon S. Allbery KF8NH" &lt;allbery@ece.cmu.edu&gt;, haskell-cafe@haskell.org<br>Date: Wednesday, May 20, 2009, 4:12 AM<br><br><div class="plainMail">(Apologies for my mutilation of ML syntax, I don't completely know the language)<br><br>Consider the ML type int list, and this function to build one:<br><br>broken_repeat :: int -&gt; int list<br>broken_repeat n = Cons(n, broken_repeat(n))<br><br>This function is recursive, and doesn't terminate; it tries to build<br>an infinite list of ints and your computer runs out of heap and/or<br>stack trying to evaluate it.<br><br>But the "chain" type doesn't have this problem; you can see it as an<br>int list that gets evaluated "on demand":<br><br>repeat :: int -&gt; chain<br>repeat(n) = Link(n, repeat)<br><br>always1 :: int -&gt; chain<br>always1(_) = Link(1, always1)<br><br>chain_take :: int * chain -&gt; int list<br>chain_take (0,_) =
 Nil<br>chain_take (n,Link(i,f)) = Cons(n, chain_take(n-1, f(i)))<br><br>But, nothing in the "chain" type stops you from passing a different<br>value to the function in the link:<br><br>weird_take :: int * int * chain -&gt; int list<br>weird_take (0,_,_) = Nil<br>weird_take (n,v,Link(i,f)) = Cons(i, weird_take(n-1,v,f(v)))<br><br>Now, it's possible that chain_take returns the same list for two<br>different "chain" inputs, but weird_take might return different lists<br>depending on how f is implemented.&nbsp; For example:<br>&nbsp; &nbsp; chain_take(5, repeat(1)) = [1,1,1,1,1]<br>&nbsp; &nbsp; chain_take(5, always1(1) = [1,1,1,1,1]<br><br>&nbsp; &nbsp; weird_take(5, 2, repeat(1)) = [1,2,2,2,2]<br>&nbsp; &nbsp; weird_take(5, 2, always1(1)) = [1,1,1,1,1]<br><br>One way to fix this is to embed the "state" of the chain in the closure itself.<br><br>So, in ML, the type<br>&nbsp;&nbsp;&nbsp;unit -&gt; X<br>is commonly called a "thunk"; it can be used to delay
 computation<br>until later, until it's demanded, just like any lazy value in Haskell.<br><br>f :: unit -&gt; Int<br>f () = 1<br><br>This f isn't very useful; it's basically the same as "1".&nbsp; But<br>consider this type:<br><br>datatype stream = Stream of (int * (unit -&gt; stream))<br><br>stream1 () = Stream(1, stream1)<br><br>stream_take :: int*stream -&gt; int list<br>stream_take(0,_) = Nil<br>stream_take(n,Stream(i,f)) = Cons(i, stream_take(n-1, f()))<br><br>Now there is no way to pass a different value like we did in<br>weird_take; there's only ().<br><br>The difference is that the state gets embedded in the closure for the thunk:<br><br>stream_ints :: int -&gt; (unit -&gt; stream)<br>stream_ints = fun n =&gt; fun () =&gt; Stream(n, stream_ints(n+1))<br><br>What you are doing here is encoding laziness; the Haskell version of this type:<br><br>&gt; data Stream = Stream !Int Stream -- !Int means the Int value is strict<br>&gt; stream1 = Stream 1
 stream1<br>&gt; stream_ints n = Stream n (stream_ints(n+1))<br><br>&gt; stream_take :: Int -&gt; Stream -&gt; [Int]<br>&gt; stream_take 0 _ = []<br>&gt; stream_take n (Stream x xs) = x : stream_take (n-1) xs<br><br>No extra (\() -&gt; ...) thunk is required, due to laziness :)<br><br>&nbsp; -- ryan<br><br>On Tue, May 19, 2009 at 4:25 PM, michael rice &lt;<a ymailto="mailto:nowgate@yahoo.com" href="/mc/compose?to=nowgate@yahoo.com">nowgate@yahoo.com</a>&gt; wrote:<br>&gt; Hi Ryan,<br>&gt;<br>&gt; I'm afraid you've lost me. Maybe if you showed how this would be used in ML<br>&gt; I would get the picture.<br>&gt;<br>&gt; Michael<br>&gt;<br>&gt; --- On Tue, 5/19/09, Ryan Ingram &lt;<a ymailto="mailto:ryani.spam@gmail.com" href="/mc/compose?to=ryani.spam@gmail.com">ryani.spam@gmail.com</a>&gt; wrote:<br>&gt;<br>&gt; From: Ryan Ingram &lt;<a ymailto="mailto:ryani.spam@gmail.com" href="/mc/compose?to=ryani.spam@gmail.com">ryani.spam@gmail.com</a>&gt;<br>&gt;
 Subject: Re: [Haskell-cafe] showing a user defined type<br>&gt; To: "michael rice" &lt;<a ymailto="mailto:nowgate@yahoo.com" href="/mc/compose?to=nowgate@yahoo.com">nowgate@yahoo.com</a>&gt;<br>&gt; Cc: "Brandon S. Allbery KF8NH" &lt;<a ymailto="mailto:allbery@ece.cmu.edu" href="/mc/compose?to=allbery@ece.cmu.edu">allbery@ece.cmu.edu</a>&gt;,<br>&gt; <a ymailto="mailto:haskell-cafe@haskell.org" href="/mc/compose?to=haskell-cafe@haskell.org">haskell-cafe@haskell.org</a><br>&gt; Date: Tuesday, May 19, 2009, 2:40 PM<br>&gt;<br>&gt; On Tue, May 19, 2009 at 7:07 AM, michael rice &lt;<a ymailto="mailto:nowgate@yahoo.com" href="/mc/compose?to=nowgate@yahoo.com">nowgate@yahoo.com</a>&gt; wrote:<br>&gt;&gt; A little further along in "The Little MLer" the ints function is replaced<br>&gt;&gt; by<br>&gt;&gt; other functions like primes and fibs, which also return Links:<br>&gt;&gt;<br>&gt;&gt; fun primes(n)<br>&gt;&gt; &nbsp; = if is_prime(n+1)<br>&gt;&gt;
 &nbsp;then Link(n+1,primes)<br>&gt;&gt; &nbsp;else primes(n+1)<br>&gt;&gt;<br>&gt;&gt; fun fibs(n)(m)<br>&gt;&gt; &nbsp; = Link(n+m,fibs(m))<br>&gt;&gt;<br>&gt;&gt; which are passed to chain_item:<br>&gt;&gt;<br>&gt;&gt; fun chain_item(n,Link(i,f))<br>&gt;&gt; &nbsp; = if eq_int(n,1)<br>&gt;&gt; &nbsp; then i<br>&gt;&gt; &nbsp; else chain_item(n-1,f(i))<br>&gt;&gt;<br>&gt;&gt; which can be called to request the nth (12th) prime number beginning at 1.<br>&gt;&gt;<br>&gt;&gt; - chain_item(12,primes(1));<br>&gt;&gt; GC #0.0.0.1.3.61:&nbsp;&nbsp; (1 ms)<br>&gt;&gt; val it = 37 : int<br>&gt;&gt; -<br>&gt;&gt;<br>&gt;&gt; So I guess the answer to your question about whether the function is ever<br>&gt;&gt; called with a different value may be, yes.<br>&gt;<br>&gt; Actually, it's not calling it with another value; notice that<br>&gt; chain_item calls f(i), with i coming directly from the chain.<br>&gt; Consider this alternate definition:<br>&gt; (I'm not sure
 the syntax is exactly right, but you get the idea)<br>&gt;<br>&gt; datatype chain =<br>&gt; &nbsp; Link of (int * ( unit -&gt; chain ))<br>&gt;<br>&gt; fun intsFrom(n) = fun unit =&gt; (n, intsFrom (n+1))<br>&gt; fun ints(n) = intsFrom n ()<br>&gt;<br>&gt; Now you *can't* call the function embedded in the link with another value.<br>&gt;<br>&gt; fun chain_item(n,Link(i,f))<br>&gt; &nbsp; = if eq_int(n,1)<br>&gt; &nbsp; then i<br>&gt; &nbsp; else chain_item(n-1,f unit)<br>&gt;<br>&gt; And this type for "chain" is almost the same as [Int] in Haskell, due<br>&gt; to laziness.<br>&gt;<br>&gt; &nbsp; -- ryan<br>&gt;<br>&gt;<br></div></blockquote></td></tr></table><br>