
{"id":24,"date":"2008-06-19T22:26:14","date_gmt":"2008-06-20T03:26:14","guid":{"rendered":"http:\/\/www.ikriv.com\/blog\/?p=24"},"modified":"2008-06-19T22:26:14","modified_gmt":"2008-06-20T03:26:14","slug":"f-another-disappointment-lazy-evaluation","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=24","title":{"rendered":"F# &#8211; Another Disappointment: Lazy Evaluation"},"content":{"rendered":"<p>After exploring &#8220;<code>lazy<\/code>&#8221; keyword in F#, I was up for some disappointments:<\/p>\n<p><font color=\"Blue\"><b>&lt;DISCLAIMER&gt;<\/b> Fast forward to the year 2012: people from <a href=\"http:\/\/www.tryfsharp.org\/\">Microsoft&#8217;s &#8220;try F#&#8221;<\/a> team pointed out that I got some things wrong here, and they probably have a point. So, take whatever follows with a grain of salt. Also, take a look at the comments.<b>&lt;\/DISCLAIMER&gt;<\/b><\/font><\/p>\n<p>* <code>lazy (bla)<\/code>  cannot be transparently used in expressions instead of <code>bla<\/code><br \/>\n* Results of lazy evaluation are not cached<br \/>\n* Parameters of lazy functions are evaluated eagerly<\/p>\n<p>Let me explain each of these points.<br \/>\n<!--more--><\/p>\n<h2>Lazy values are not transparent<\/h2>\n<p>Lazy values such as <code>lazy x<\/code> have a template type <code>Lazy&lt;'a&gt;<\/code>, or in C# terms <code>Lazy&lt;T&gt;<\/code>. This type does not inherit operations of <code>T<\/code>. If you have two lazy integers, you cannot lazily add them via &#8216;+&#8217;: <code>(lazy 2) + (lazy 3)<\/code> won&#8217;t work. To lazily add two lazy integers you will have to write a special function along the lines of:<\/p>\n<pre><code>let lazy_add x y =\n lazy( Lazy.force(x) + Lazy.force(y) )\n<\/code><\/pre>\n<p>You <b>must<\/b> explicitly call <code>Lazy.force()<\/code> or similar function to obtain the value of the lazy expression.<\/p>\n<p>This all makes laziness in F# very explicit. You manually say when things are lazy, you manually say when you want to force the calculation, and you cannot manipulate lazy objects as if they were regular objects.<\/p>\n<h2>Lazy Evaluation Results Are Not Cached<\/h2>\n<p>In purely functional languages like Haskell, lazy evaluation results are cached my default. If the system already calculated the value of <code>foo(42)<\/code>, it will not calculate it again. This makes sense, since it is assumed that function don&#8217;t have side effects.<\/p>\n<p>F# does not cache lazy evaluated values. This can be demonstrated by the following code:<\/p>\n<pre><code>#light\nopen System\n\nlet input x =\n lazy\n (\n  printf \"Please enter value for \"\n  print_any x\n  printf \": \"\n  Console.ReadLine()\n )\n\nlet a = (input 42) |> Lazy.force\nlet b = (input 42) |> Lazy.force\n<\/code><\/pre>\n<p>The code requests the input twice. If the value of <code>input 42<\/code> were cached, it would request the input only once. This is exactly what happens if we cache the value manually:<\/p>\n<pre><code>\nlet cache = input 42\nlet a = cache |> Lazy.force\nlet b = cache |> Lazy.force\n<\/code><\/pre>\n<p>Caching the values manually requires writing code, and it may lead to threading issues. Consider this memoization sample from <a href=\"http:\/\/www.amazon.com\/Expert-F-Experts-Voice-Net\/dp\/1590598504\/ref=pd_bbs_sr_1?ie=UTF8&#038;s=books&#038;qid=1213829619&#038;sr=8-1\">&#8220;Expert F#&#8221; book<\/a>:<\/p>\n<pre><code>let fibFast =\n let t = new System.Collections.Generic.Dictionary&lt;int,int&gt;()\n let rec fibCached n =\n  if t.ContainsKey(n) then t.[n]\n  else if n <= 2 then 1\n  else let res = fibCached(n-1) + fibCached(n-2)\n    t.Add(n,res)\n    res\n fun n -> fibCached n\n<\/code><\/pre>\n<p>This example uses a (local) dictionary, which would require locks if we wanted to parallelize <code>fib_cached<\/code>.<\/p>\n<h2>Parameters of Lazy Functions are Evaluated Eagerly<\/h2>\n<p>Consider:<\/p>\n<pre><code>let lazy_add a b =\n lazy (a+b)\n\nlet use_lazy_add x =\n lazy_add func1(x) func2(x)\n<\/code><\/pre>\n<p>The calls to <code>func1()<\/code> and <code>func2()<\/code> will be evaluated eagerly. Only the addition of the results will be lazy. This is not very bad per se, but it hinders functional decomposition. If I have nested function calls, &#8220;laziness&#8221; must be applied on the very top level. Consider:<\/p>\n<pre><code>let f1 x = ...\nlet f2 x = ...\n\n\/\/ use f1 lazily\nlet r1 = f1 42\nlet r2 = f2 18\n\nlet lazy_add x y =\n  lazy( x+y )\n\nlet add_result = lazy_add 10 20\nlet add_result2 = lazy_add r1 r2 \/\/ oops! this won't work\nlet add_result3 = lazy( r1+r2 ) \/\/ that won't work either\nlet add_reslut4 = lazy_add Lazy.force(r1) Lazy.force(r2) \/\/ will eagerly call f1, f2\nlet add_result5 = lazy (Lazy.force(r1) + Lazy.force(r2)) \/\/ this will do what we want\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>After exploring &#8220;lazy&#8221; keyword in F#, I was up for some disappointments: &lt;DISCLAIMER&gt; Fast forward to the year 2012: people from Microsoft&#8217;s &#8220;try F#&#8221; team pointed out that I got <a href=\"https:\/\/ikriv.com\/blog\/?p=24\" class=\"more-link\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"Layout":"","footnotes":""},"categories":[10],"tags":[9],"class_list":["entry","author-ikriv","has-more-link","post-24","post","type-post","status-publish","format-standard","category-fsharp","tag-fsharp"],"_links":{"self":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/24","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=24"}],"version-history":[{"count":0,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/24\/revisions"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}