如何在Lua函数上应用元表以启用它们之间的自定义操作符?

我正在尝试为特定函数设置元表,以启用它们之间的函数组合自定义操作符。

我希望在我的库中引入一个组合操作符的原因是,我不想像这样嵌套参数括号: f(g(h(x))) 而是像这样: f * g * h(x) 或类似的不需要嵌套括号的操作符。

到目前为止,我有两种方法来实现我的目标:

  1. 尝试为Lua函数设置__mul元方法,但我不确定如何设置。

  2. 通过提供__call__mul的元方法,重新定义所有可组合的函数为可调用的函数组合表。

今天我写了一个实验性的(以及工作正常的)[实现](https://gist.github.com/david-tamar/cd4b8d27fb1282f227f31a15bd501f63) ,用于第二种方法(函数组合表)。 但我认为它不太优雅,实际上只是语法糖却有很大的内存和处理开销。它非常复杂,因为Lua将自定义操作符左依赖性地计算,而函数组合实际上是右依赖性(当我实现它时,我错误地这样认为,结果是为一个完全不同的原因。详情见注释)。

我当前尝试使用函数和元表来实现第一种方法,它看起来像这样:

local compositable =
{
    __mul = function(a, b)
        a(b)
    end
}

local function f(x) return x*x end
local function g(x) return -x end

setmetatable(f, compositable) --错误,需要表格,但获得的是函数。
setmetatable(g, compositable) -- "

local result = f * g(4)

print(result) -- 预期结果:-16

但这不起作用,似乎Lua只允许使用元表设置Lua表和字符串。

点赞
用户734069
用户734069

虽然 Lua 的所有值都可以拥有元表,但是 setmetatable 只能 为表设置元表。表和完整的用户数据可以将元表设置在各自的值上,而不同类型的值则共享每个类型的元表。例如,所有的字符串都有相同的元表。

所以你不能为函数设置元表,但是你可以为 所有函数 设置元表。只有 debug 库可以通过 debug.setmetatable 实现这一点。同样,这将适用于 _所有的函数_。

2019-08-03 13:28:28
用户107090
用户107090

如评论所提及的,你需要编写 (f * g)(x)。然后,下面的代码将运行。

debug.setmetatable(function()end,
    {__mul=function (f,g) return function (x) return f(g(x)) end end})

function f(x) return x*x end
function g(x) return -x end

print((f*g)(2))
print((g*f)(2))

这段代码有点浪费,因为它在每次调用中都创建了一个组合函数。

2019-08-03 15:17:58