domingo, 13 de março de 2011

Decoradores em Lua

@



Um recurso extremamente útil em Python é o uso de decoradores.

Por exemplo, um decorador que memoíze o resultado de uma função:

def memo(func, buffer={}):
def wrapper(*args):
if args in buffer:
response = buffer[args]
else:
response = buffer[args] = func(*args)
return response

return wrapper


Assim funções como o cálculo recursivo da sequência de Fibonacci se tornam menos custosas:
@memo
def fibonacci(n):
if n < 2:
return 1
else:
return fibonacci(n - 2) + fibonacci(n - 1)


Observação: memoização consome muita memória!

É possível ver que, em Python, decoradores são extremamente fáceis de se implementar e usar, o que permite usos bastantes complexos, como a orientação a aspecto.

Lua também suporta decoradores, mas de uma forma um pouco menos intuitiva, mais complexa e totalmente macetada.

Para a criação de decoradores em Lua, é usada a sobrecarga do operador de concatenação, como sugerido na literatura de referência.

Para criarmos então o decorador de memoização, precisamos de uma metatabela que sobrecarregue o operador:
local mt = {
__concat = function(self, func)
return function(...)
local response
local args = serialize(...)
if self[args] then
response = self[args]
else
response = func(...)
self[args] = response
end
return response
end
end,
}


A função serialize() não existe, então temos de criá-la:
local function serialize(...)
local response = ""
local i, v
for i, v in ipairs {...} do
response =
response .. "[" .. ("%g"):format(i) .. "] = " ..
("%g"):format(v) .. ", "
end
return response
end


Agora criamos o decorador:
function memo()
return setmetatable({}, mt)
end


Isso tudo pode ser colocado em módulo, chamado memo.lua por exemplo. Na última linha do módulo coloque:
return memo


Agora, para usar o decorador:
require "memo"

fibonacci =
memo() ..
function(n)
if n < 2 then
return 1
else
return fibonacci(n - 2) + fibonacci(n - 1)
end
end


O uso do decorador está na linha: memo() .. – a sintaxe não é tão elegante quanto a de Python – @memo –, mas funciona da mesma forma, inclusive a criação de cadeias de decoradores.

A criação de decoradores em Lua também não é tão intuitiva e simples quanto em Python, em função da diferença de filosofias entre as duas linguagens, mas com o hábito se torna um recurso poderoso.

[]’s
Cacilhας, La Batalema