<html><head><style type="text/css"><!-- DIV {margin:0px;} --></style></head><body><div style="font-family:times new roman, new york, times, serif;font-size:12pt"><div>Dear Pieter,<br><br>&gt; the array elements will be updated too often.<br><br>I thought that <br> | a.[n] &gt; 0&nbsp; &nbsp; &nbsp; &nbsp; = a![n]<br>in Fib3_ avoided that, asking first if one ever computed (f n) before. Of course only works for strictly positive f :: Int -&gt; Int<br><br>&gt; using some accumulators the use of an array can be avoided (as Attila <br>&gt; pointed out):<br><br>Sure, I think the exercise here is implementing memoization in Clean. No?<br><br>Actualy, this is what I think is a "general" memoization technique in Clean. (general in quotes because it only works for strictly positive Int-&gt;Int)<br><br>--------------------------------------------------<br>module fib<br><br>import StdEnv<br><br>/* the general function */<br>fib :: Int -&gt; Int<br>fib n
 <br>&nbsp;&nbsp;&nbsp; | n &lt;= 1&nbsp;&nbsp;&nbsp; = 1<br>&nbsp;&nbsp;&nbsp; | otherwise&nbsp;&nbsp;&nbsp; = fib (n - 1) + fib (n - 2)<br><br>/* "general" memoization */ <br>memo :: *{Int} (Int -&gt; Int) Int -&gt; (Int, *{Int})<br>memo a f n<br>&nbsp;&nbsp;&nbsp; | size a &lt; n&nbsp;&nbsp;&nbsp; = abort "n out of range"<br>&nbsp;&nbsp;&nbsp; | a.[n] &gt; 0&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; = a![n]<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; = {a &amp; [n] = (f n)}![n] <br><br>/* this is our memoizated fib */<br>memoFib = memo (createArray 100 0) fib<br><br>/* and this shows my ignorance on how to select the second item in a tuple as I need this down there ;-) */<br>sec (x, _) = x<br><br>Start :: {Int}<br>Start = {fibm 7, fibm 10}<br>&nbsp;&nbsp;&nbsp; where<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fibm n = sec (memoFib n)<br>--------------------------------------------------<br></div><div
 style="font-family: times new roman,new york,times,serif; font-size: 12pt;"><br>So, my claim is that in Start, fib 7 is computed only once. Is this right? <br><br>By the way, is there any easy (ala unsafeIO or something) to check this in fib or its friends?<br><br>cheers<br>Carlos<br><br><div style="font-family: arial,helvetica,sans-serif; font-size: 13px;">----- Original Message ----<br>From: Pieter Koopman &lt;pieter@cs.ru.nl&gt;<br>To: Carlos Aya &lt;carlosayam@yahoo.com.au&gt;<br>Cc: clean-list@science.ru.nl; Attila Ondi &lt;aondi@fit.edu&gt;<br>Sent: Monday, 20 October, 2008 11:02:19 PM<br>Subject: Re: [clean-list] Question on destructive array updates<br><br>Dear Carlos,<br><br>your code for Fib3 will work correctly, but due to the double recursions <br>the array elements will be updated too often. Hence the complexity will <br>be even bad as in a naive definition. This can be avoided by computing <br>from the low indices to the high
 ones.<br><br>fibArray :: !Int -&gt; Int<br>fibArray n<br> | n&lt;0&nbsp; = abort ("fibArray not defined for argument "+++toString n)<br>&nbsp; &nbsp; &nbsp; &nbsp; = g 2 (createArray (n+1) 1)<br>where<br>&nbsp; &nbsp; g :: !Int *{#Int} -&gt; Int<br>&nbsp; &nbsp; g i array<br>&nbsp; &nbsp;  | i&lt;=n<br>&nbsp; &nbsp; &nbsp; &nbsp; # (a,array) = array![i-1]<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (b,array) = array![i-2]<br>&nbsp; &nbsp; &nbsp; &nbsp; = g (i+1) {array &amp; [i]=a+b}<br>&nbsp; &nbsp; &nbsp; &nbsp; = array.[n]<br><br>using some accumulators the use of an array can be avoided (as Attila <br>pointed out):<br><br>fibAcc :: !Int -&gt; Int<br>fibAcc n<br> | n&lt;0&nbsp; = abort ("fibAcc not defined for argument "+++toString n)<br>&nbsp; &nbsp; &nbsp; &nbsp; = f n 1 1<br>where<br>&nbsp; &nbsp; f :: !Int !Int !Int -&gt; Int<br>&nbsp; &nbsp; f 0 a b = a<br>&nbsp; &nbsp; f n a b = f (n-1) b (a+b)<br><br>Have fun,<br><br>Pieter Koopman<br><br>Carlos Aya
 wrote:<br>&gt; Hi Attila,<br>&gt;<br>&gt; It's been a while for me too... I tried your code and the problem is<br>&gt;<br>&gt;&nbsp; &gt;&gt;&gt; a.[n] &gt; 0 = (a.[n], a)<br>&gt;<br>&gt; There are two uses of 'a' on the RHS. Fortunately, Clean comes with <br>&gt; a![n], which does precisely what you want, returns a tuple with the <br>&gt; value and the array for future use. So, if I understood what you <br>&gt; wanted, the code ended like (omitting your other fib's, and I put <br>&gt; Fib3_ top level ...)<br>&gt;<br>&gt; ---<br>&gt; module fib<br>&gt;<br>&gt; import StdEnv<br>&gt;<br>&gt; Fib3 :: Int -&gt; Int<br>&gt; Fib3 n<br>&gt; | n &lt; 0 = abort "Fib3: Called with negative parameter"<br>&gt; | otherwise = res<br>&gt;&nbsp; &nbsp;  where<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  (res, _) = Fib3_ n (createArray (n+1) 0)<br>&gt;<br>&gt; Fib3_ :: Int *{Int} -&gt; (Int, *{Int})<br>&gt; Fib3_ n a<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; | size a &lt; n&nbsp;
 &nbsp; = abort "cannot store fib(n) in a"<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; | a.[n] &gt; 0&nbsp; &nbsp; &nbsp; &nbsp; = a![n]<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; | n == 0&nbsp; &nbsp; &nbsp; &nbsp; = {a &amp; [0] = 1}![0]<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; | n == 1&nbsp; &nbsp; &nbsp; &nbsp; = {a &amp; [1] = 1}![0]<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; | otherwise<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # (res1, a) = Fib3_ (n-1) a<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # (res2, a) = Fib3_ (n-2) a<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  = {a &amp; [n] = res1 + res2}![n]<br>&gt;<br>&gt;<br>&gt; Start :: Int<br>&gt; Start = Fib3 7<br>&gt; ---<br>&gt;<br>&gt; Note also the use of # to reuse the 'a' variable. So, it is unique in <br>&gt; the 'otherwise' branch as well.<br>&gt;<br>&gt; This can be generalized to memorize any Int -&gt; Int function, later...<br>&gt;<br>&gt; Hope this helps<br>&gt;<br>&gt; Carlos Aya<br>&gt;<br>&gt;
 -------------------------------<br>&gt; Message: 1<br>&gt; Date: Fri, 17 Oct 2008 15:02:25 -0400 (EDT)<br>&gt; From: "Attila Ondi" &lt;<a ymailto="mailto:aondi@fit.edu" href="mailto:aondi@fit.edu">aondi@fit.edu</a> &lt;mailto:<a ymailto="mailto:aondi@fit.edu" href="mailto:aondi@fit.edu">aondi@fit.edu</a>&gt;&gt;<br>&gt; Subject: [clean-list] Question on destructive array updates<br>&gt; To: <a ymailto="mailto:clean-list@science.ru.nl" href="mailto:clean-list@science.ru.nl">clean-list@science.ru.nl</a> &lt;mailto:<a ymailto="mailto:clean-list@science.ru.nl" href="mailto:clean-list@science.ru.nl">clean-list@science.ru.nl</a>&gt;<br>&gt; Message-ID:<br>&gt;&nbsp; &nbsp;  &lt;<a ymailto="mailto:3441.163.118.203.36.1224270145.squirrel@webaccess.fit.edu" href="mailto:3441.163.118.203.36.1224270145.squirrel@webaccess.fit.edu">3441.163.118.203.36.1224270145.squirrel@webaccess.fit.edu</a> <br>&gt; &lt;mailto:<a
 ymailto="mailto:3441.163.118.203.36.1224270145.squirrel@webaccess.fit.edu" href="mailto:3441.163.118.203.36.1224270145.squirrel@webaccess.fit.edu">3441.163.118.203.36.1224270145.squirrel@webaccess.fit.edu</a>&gt;&gt;<br>&gt; Content-Type: text/plain;charset=iso-8859-1<br>&gt;<br>&gt; Hi all,<br>&gt;<br>&gt; I was trying to refresh my knowledge in Clean and picked to implement the<br>&gt; Fibonacci series.&nbsp; The obvious recursive implementation (Fib) was trivial<br>&gt; and then I tried to move on to use some tricks to speed up the<br>&gt; computation.&nbsp; The first idea was to use lists to store the already<br>&gt; computed values (Fib2).&nbsp; This worked, but did not prove any faster<br>&gt; (according to the profiler) mostly because of the many list traversals.<br>&gt;<br>&gt; Then I tried my hands using arrays as I remembered they provide constant<br>&gt; access time to their elements and can also be updated destructively (to<br>&gt; avoid
 re-creating an almost identical array).&nbsp; The resulting function<br>&gt; (Fib3) is pretty similar to the one using lists (Fib2), but I cannot get<br>&gt; it to compile (complaining about type coercion in the line "| a.[n] &gt; 0 =<br>&gt; (a.[n], a)" in the function Fib3_ "Uniqueness error: attribute at<br>&gt; indicated position could not be coerced *(Int,^{u:Int})").&nbsp; No matter what<br>&gt; I tired (e.g. unnamed uniqueness type annotations, strict and/or unboxed<br>&gt; elements), I could not get rid of the compiler error.&nbsp; All&nbsp; my efforts to<br>&gt; find some explanation to the problem through web search were futile, so<br>&gt; I'd like to ask the list a few questions:<br>&gt;<br>&gt; 1) Why does the compiler (just downloaded the latest 2.2) present me with<br>&gt; an error when I don't reuse the array, only an element of it (or was<br>&gt; trying to at least) -- shouldn't possible multiple references be handled<br>&gt; properly by
 the runtime?<br>&gt;<br>&gt; 2) Can the calculation of the Fibonacci sequence be implemented with the<br>&gt; use of a destructive array?&nbsp; If yes how (or how to fix my program) -- if<br>&gt; not, why not?<br>&gt;<br>&gt;<br>&gt; And finally, here is my program.&nbsp; It also includes a linear calculation of<br>&gt; the Fibonacci numbers (Fib4) without using any array or list components<br>&gt; (just accumulators) for completeness -- I hope my email client does not<br>&gt; mess up the indentations too much.<br>&gt;<br>&gt; Thanks,<br>&gt; Attila Ondi<br>&gt;<br>&gt;<br>&gt; =================<br>&gt; module Fibonacci<br>&gt;<br>&gt; import StdEnv<br>&gt;<br>&gt; Fib :: Int -&gt; Int<br>&gt; Fib 0 = 1<br>&gt; Fib 1 = 1<br>&gt; Fib n = Fib (n-1) + Fib (n-2)<br>&gt;<br>&gt;<br>&gt; Fib2 :: Int -&gt; Int<br>&gt; Fib2 n<br>&gt; | n &lt; 0 = abort "Fib2: Called with negative parameter"<br>&gt; | otherwise =<br>&gt;&nbsp; &nbsp;  let<br>&gt;&nbsp; &nbsp;
 &nbsp; &nbsp;  (res, _) = Fib2_ n []<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib2_ :: Int [Int] -&gt; (Int, [Int])<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib2_ 0 l=:[x0 : xs] = (x0, l)<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib2_ 0 _ = (1, [1])<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib2_ 1 l=:[x0, x1 : xs] = (x1, l)<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib2_ 1 _ = (1, [1, 1])<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib2_ n l<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  | length l &gt;= n+1 =<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  let<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  nth :: Int [Int] -&gt; Int<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  nth 0 [x : _] = x<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  nth n [_ : xs] = nth (n-1) xs<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  nth _ [] = abort "nth: Not enough elements in list"<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
 in (nth n l, l)<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  | otherwise =<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  let<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (res1, resl1) = Fib2_ (n-2) l<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (res2, resl2) = Fib2_ (n-1) resl1<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  in (res1 + res2, resl2)<br>&gt;&nbsp; &nbsp;  in res<br>&gt;<br>&gt;<br>&gt; Fib3 :: Int -&gt; Int<br>&gt; Fib3 n<br>&gt; | n &lt; 0 = abort "Fib3: Called with negative parameter"<br>&gt; | otherwise =<br>&gt;&nbsp; &nbsp;  let<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  (res, _) = Fib3_ n (createArray n 0)<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib3_ :: Int *{Int} -&gt; (Int, *{Int})<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib3_ n a<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  | size a &lt; n+1 = abort "Fib3_: Array is smaller than required"<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  | a.[n] &lt; 0 = abort "Fib3_:
 Invalid array value"<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  | a.[n] &gt; 0 = (a.[n], a)<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  | otherwise =<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  let<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (res1, resa1) = Fib3_ (n-1) a<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (res2, resa2) = Fib3_ (n-2) resa1<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  in (res1 + res2, resa2)<br>&gt;&nbsp; &nbsp;  in res<br>&gt;<br>&gt;<br>&gt; Fib4 :: Int -&gt; Int<br>&gt; Fib4 n<br>&gt; | n &lt; 0 = abort "Fib4: Called with negative parameter"<br>&gt; | otherwise =<br>&gt;&nbsp; &nbsp;  let<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  (_, _, res) = Fib4_ n 1 1<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib4_ :: Int Int Int -&gt; (Int, Int, Int)<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib4_ 0 tmp _ = (0, 0, tmp)<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  Fib4_ 1 _ acc = (0, 0, acc)<br>&gt;&nbsp; &nbsp; &nbsp;
 &nbsp;  Fib4_ n tmp acc<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;  | otherwise = Fib4_ (n-1) acc (acc + tmp)<br>&gt;&nbsp; &nbsp;  in res<br>&gt;<br>&gt; Start :: [Int]<br>&gt; Start = [Fib 7, Fib2 7, Fib3 7, Fib4 7]<br>&gt; =================<br>&gt;<br>&gt;<br>&gt;<br>&gt;<br>&gt; ------------------------------<br>&gt;<br>&gt; _______________________________________________<br>&gt; clean-list mailing list<br>&gt; <a ymailto="mailto:clean-list@science.ru.nl" href="mailto:clean-list@science.ru.nl">clean-list@science.ru.nl</a> &lt;mailto:<a ymailto="mailto:clean-list@science.ru.nl" href="mailto:clean-list@science.ru.nl">clean-list@science.ru.nl</a>&gt;<br>&gt; <a href="http://mailman.science.ru.nl/mailman/listinfo/clean-list" target="_blank">http://mailman.science.ru.nl/mailman/listinfo/clean-list</a><br>&gt;<br>&gt;<br>&gt; End of clean-list Digest, Vol 47, Issue 10<br>&gt; ******************************************<br>&gt;<br>&gt; Send instant messages to your
 online friends <br>&gt; <a href="http://au.messenger.yahoo.com" target="_blank">http://au.messenger.yahoo.com</a><br>&gt; ------------------------------------------------------------------------<br>&gt;<br>&gt; _______________________________________________<br>&gt; clean-list mailing list<br>&gt; <a ymailto="mailto:clean-list@science.ru.nl" href="mailto:clean-list@science.ru.nl">clean-list@science.ru.nl</a><br>&gt; <a href="http://mailman.science.ru.nl/mailman/listinfo/clean-list" target="_blank">http://mailman.science.ru.nl/mailman/listinfo/clean-list</a><br>&gt;&nbsp;  <br></div></div></div><br>Send instant messages to your online friends http://au.messenger.yahoo.com </body></html>