Hey Petr, interesting post! (and links)<div>I imagine that one issue that would make it not a default activity by GHC is that this sort of strategy has the following implications:</div><div><br></div><div>1) ghc in general doesn&#39;t always want to inline.... in general, inlining increases the size of code! and depending on how that happens that can increase compilation time and sometime decrease performance. That said, there are many instances where perfomance is </div>

<div><br></div><div>2) This approach *can* be extended to mutually recursive functions, but again, the naive inlining to &quot;depth k&quot; would have on the order of ~ 2^k code blow up potentially (or so I think offhand)</div>

<div><br></div><div>theres probably a few other problems with doing this automatically, but it looks like a nice performance trick I may consider using time.</div><div><br></div><div>cheers</div><div>-Carter</div><div><br>

</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Nov 8, 2012 at 10:00 AM, Petr P <span dir="ltr">&lt;<a href="mailto:petr.mvd@gmail.com" target="_blank">petr.mvd@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  Hi,<div><br></div><div>recently I found out that some recursive functions can be greatly optimized just by rewriting them using `let` so that they&#39;re not recursive themselves any more (only the inner let is). To give an example:</div>



<div><br></div><div><div>&gt; fix :: (a -&gt; a) -&gt; a</div><div>&gt; fix f = f (fix f)</div></div><div><br></div><div>isn&#39;t optimized, because it&#39;s a recursive function and so it isn&#39;t inlined or anything. However, defining it as</div>



<div><br></div><div>&gt; fix f = let x = f x in x</div><div><br></div><div>makes it much more efficient, since `fix` is not recursive any more, so it gets inlined and then optimized for a given argument `f`.</div><div>(See <a href="http://stackoverflow.com/questions/12999385/why-does-ghc-make-fix-so-confounding" target="_blank">http://stackoverflow.com/questions/12999385/why-does-ghc-make-fix-so-confounding</a>)</div>



<div><br></div><div>Another example is the well-known generic catamorphism function:</div><div><br></div><div>&gt; newtype Fix f = Fix { unfix :: f (Fix f) }</div><div>&gt;</div><div><div>&gt; catam :: (Functor f) =&gt; (f a -&gt; a) -&gt; (Fix f -&gt; a)</div>



<div>&gt; catam f = f . fmap (catam f) . unfix</div></div><div><br></div><div>is not optimized. When `catam` is used on a data structure such as [] or a tree, at each level `fmap` creates new constructors that are immediately consumed by `f`. But when written as</div>



<div><br></div><div><div>&gt; catam f = let u = f . fmap u . unfix in u</div></div><div><br></div><div>this gets inlined and then optimized, and constructor creation/consumption is fused into very effective code.</div><div>



(See <a href="http://stackoverflow.com/q/13099203/1333025" target="_blank">http://stackoverflow.com/q/13099203/1333025</a>)</div><div><br></div><div>As one comment asked, this seems like something GHC could do automatically. Would it be difficult? Is there a reason against it? I suppose in cases where it doesn&#39;t help, the additional `let` would get optimized away, so no harm would be done. And in cases like `fix` or `catam` the gain would be substantial.<br>



</div><div><br></div><div>  Best regards,</div><div>   Petr</div>
<br>_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
<br></blockquote></div><br></div>