Closures without thinking. Was Re: A not stupid question (no questions are stupid)

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Closures without thinking. Was Re: A not stupid question (no questions are stupid)

RLak
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


Reply | Threaded
Open this post in threaded view
|

Re: Closures without thinking

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

Thanks for the examples, I'll try to learn thinking more 'closurely' at the
first suitable project (I've found that actually using concepts in real
work makes them stick much better in one's mind).

  .Enrico.