[Haskell-cafe] Eta-expansion destroys memoization?

Luke Palmer lrpalmer at gmail.com
Thu Oct 7 08:44:45 EDT 2010


On Thu, Oct 7, 2010 at 6:17 AM, Brent Yorgey <byorgey at seas.upenn.edu> wrote:
> The source code seems to be easy to read, but I don't think I understand that. For me I think if I change the first line from
> fib = ((map fib' [0 ..]) !!)
> to
> fib x = ((map fib' [0 ..]) !!) x
> It should do the same thing since I think the previous version is just an abbreviation  for the second one.

Semantically, yes.  And it's possible that ghc -O is clever enough to
notice that.  But at least under ghci's naive evaluation strategy,
lambdas determine the lifetime of expressions. Any expression within a
lambda will be re-evaluated each time the lambda is expanded.  Thus:

  fib = (map fib' [0..] !!)        -- fast
  fib = \x -> map fib' [0..] !! x        -- slow
  fib = let memo = map fib' [0..] in \x -> memo !! x -- fast

The section works because "(a %^&)"  (for some operator %^&) is short
for "(%^&) a" and "(%^& a)" is short for "flip (%^&) a".  Sections
don't expand into lambdas.

In other words, in the middle expression, there is a new "map fib'
[0..]" for each x, whereas in the others, it is shared between
invocations.

Does that make sense?

Luke


More information about the Haskell-Cafe mailing list