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