lua-users home
lua-l archive

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


I didn't mention that one of the odd uses of the memoise tag method
generator is writing local recursive functions in Lua 4.0.

The memoiser function (in a previous e-mail) has the interface

table = memoiser(function)

and generates a table which happens to mirror a function (of one argument)
but recording all the values generated by the function. The table has a
"function" tag method, so it's callable as well as being indexable. But
since it's a table, it can be created as a local and then "filled in", as
it were. I do that with a slight modification to the memoiser function,
giving it a second optional argument which defaults to a new table. (using
"self or {}" so it would default to a new table even if you provided false
or nil as a second argument :-) Then I can say:

local f = {}
f = memoiser(function(k) ... %f(k-1) ...)

Sometimes I don't actually want to memoise, so I use a version which
doesn't actually record the return values.

Although this may seem off-the-wall and bizarre, having a function which is
also a table provides some interesting possibilities. For example, it lets
you specify "special values" for the function without having to clutter the
code up with lots of if statements, or developing a new "special values"
procedure every time you need one. I call these things "functables" because
they are somewhere on the interface between a function and a table.

Simplified example:

plural = functable(function(word) return word .. "s" end)
plural["mouse"] = "mice"
plural["ox"] = "oxen"
... etc ...

This is actually faster than writing the check in the function, because the
special case check is handled by Lua internally (in the gettable function,
which starts by doing a table lookup and then calls the function if
necessary). The version of functable that I use does not actually do the
whole thing of checking for nils, because that really slows things down, so
it doesn't have a gettable TM, and it blows up if you specify nil as an
argument. It does, however, correctly pass through nil return values -- the
version of memoiser I normally use, which doesn't deal with nil at all,
won't be able to correctly memoise nil return values, but the version I
roughly typed into the e-mail message does, at a certain performance hit.

Honest, I will post the entire tag method library next week. I promise.

Rici