lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Enrico Colombini escribió:

> As for your intriguing second example, I am well aware of the power of
> closures on the rational level (that is a closure over 'tab', right?),
but
> I still haven't reached the stage where I could use them without thinking
> things over first (despite reading "The little lisper"). I suppose a bit
of
> exercise is in order.

Yes, exactly. Ah, the little lisper... yes, indeed.

While closures can do wierd and wonderful things, there is a really simple
idiom that can certainly be used without much thought. The situation is
that you have a function of two or more arguments, and the function is
going to think about one of those arguments quite a bit before it produces
a result; however, it is quite normal for that argument to be repeated. An
example of this situation is the search pattern in a string library which
compiles regexes, but I'm sure you can think of many more examples.

One way to do this is to memoise the result of the thought in a hidden
table (dictionary, whatever) and this is quite common in regex libraries.
However, functional languages give another alternative: just build a
function and let the library user worry about keeping it or not.

Here is a really simple example. The pattern we're working with is this:

function(a, b) --- do something -- return v end

-->

function(a) return function(b) -- do something -- return v end end

This creates a function with a "pre-applied". (In Lua 4.0 you also have to
replace all the instances of "a" in  -- do something -- with "%a". In Lua
4.1 this is not necessary.)


Ej:

function logarithm(a, b)
  -- computes log base a of b
  return log(b) / log(a)
end

-->

function logmaker(a) return function (b)
    return log(b) / log(%a)
end end

But I don't have to compute log(a) every time, so I move it up a level:

function logmaker(a)
  local loga = log(a)
  return function(b)
    return log(b) / %loga
  end
end

And now I can define:

log2 = logmaker(2)
log10 = logmaker(10)

which are functions, so I can use them normally:

bits = log2(foo)
digits = log10(foo)

------------------------------
This is quite efficient. Lua does not make a separate copy of the code for
each function produced; all it does is create what is called a "closure"
which consists of a pointer to the code and the "closed variables". So what
you get is sort of like this:

log2: ->unnamed function 1
     2

log10: ->unnamed function 1
     10

unnamed function 1:
  parameter list: (b)
  closures: (%loga)
  code:
    return log(b) / %loga

------------------------------

Hope that helps.

Rici