<br><br>On Thu, Sep 10, 2009 at 5:46 PM, Luke Palmer &lt;<a href="mailto:lrpalmer@gmail.com">lrpalmer@gmail.com</a>&gt; wrote:<br>&gt; However, because the body of cache didn&#39;t depend on f, we can use<br>&gt; lambda calculus rules to lift the let outside the lambda.  So your<br>
&gt; transformation is completely valid...  And yet, the original code<br>&gt; works, and Bulat&#39;s equivalent code does not (in fact you can make a<br>&gt; segfault using it).<br>&gt;<br>&gt; I wouldn&#39;t dare say the original code is &quot;correct&quot; though, since a<br>
&gt; valid transformation can break it.  Compilers do valid<br>&gt; transformations.<br>&gt;<br>&gt; O unsafePerformIO, how I love thee...<br><br>Right, which is why you should write it like this:<br><br><span style="font-family: courier new,monospace;">memoIO :: Ord a =&gt; (a -&gt; b) -&gt; IO (a -&gt; IO b)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">memoIO f = do</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">    cache &lt;- newIORef M.empty</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">    return $ \x -&gt; do</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">        m &lt;- readIORef cache</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">        case M.lookup x m of</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">            Just y -&gt; return y</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">            Nothing -&gt; do let res = f x</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">                          writeIORef cache $ M.insert x res m</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">                          return res<br><br>memo :: Ord a =&gt; (a -&gt; b) -&gt; (a -&gt; b)<br>memo f = unsafePerformIO $ do<br>    fmemo &lt;- memoIO f<br>    return (unsafePerformIO . fmemo)<br>
</span><br>I don&#39;t think there is any valid transformation that breaks this, since the compiler can&#39;t lift anything through unsafePerformIO.  Am I mistaken?<br><br>  -- ryan<br><br>