[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Closures without thinking. Was Re: A not stupid question (no questions are stupid)
- From: RLake@...
- Date: Mon, 14 Jan 2002 18:27:42 -0500
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