在 lua 中定义逻辑运算符

Defining logical operator implies in lua

print("i", "j", "i & j")
for i = 0,1 do
   for j=0,1 do
   print(i, j, i & j)
   end
end

以上代码在 Lua 中运行良好。它给出以下输出。

i   j   i & j
0   0   0
0   1   0
1   0   0
1   1   1

我想定义另一个运算符implies。它是条件逻辑运算符。结果p implies q只有当p为真且q为假时才为假。

print("i", "j", "i implies j")
for i = 0,1 do
   for j=0,1 do
   print(i, j, i implies j)
   end
end

我希望上面的代码能够工作。它应该输出以下内容。

i   j   i implies j
    0   0   1
    0   1   1
    1   0   0
    1   1   1

到目前为止,我已经成功地定义了隐含函数,但似乎并没有太大用处。当然我可以写 implies(i,j) 但我想要类似于 & 或 | 的运算符我可以使用。所以基本问题是复制逻辑运算符 & 或 | 的定义来自 lua。这是隐含函数(不是运算符)的代码。

function implies(a,b)
   if a then
        return b
    else
        return True
  end
end

Lua 没有为 user-defined 运算符提供条件。

CustomOperators

但是如果 i 和 j 是布尔值,你可以使用:

i and j or true

它不适用于 0 和 1,因为对于 LUA 它们都是真的!

“数字”数据类型有两个可用的元方法:__call__index

debug.setmetatable(0, {__call = function(a, b) return a~1|b end})
-- Now you can use "(i)(j)" for "i implies j"

print("i", "j", "(i)(j)")
for i = 0,1 do
   for j = 0,1 do
      print(i, j, (i)(j))
   end
end

OOP-style 调用

如果它真的必须是中缀的话,这会变得相当棘手。对于 OOP-ish object:method(params) 语法简单地使用 metatables 怎么样?

假设 implies 定义为

local function _implies(a, b)
    if a ~= 0 then return b end
    return 1
end

这将实现为

debug.setmetatable(0, {__index = {
    implies = _implies
}})

并用作

i:implies(j)

如果您想要更简单的点语法,请考虑使用柯里化:

debug.setmetatable(0, {__index = {
    implies = function(a) return function(b) return _implies(a, b) end end
}})

用作

i.implies(j)

通过使用 __call 元方法并传递一个函数名,可以实现更“infix-ish”的表示法:

debug.setmetatable(0, {__index = {
    implies = function(a) return function(b) return _implies(a, b) end end
}, __call = function(self, index) return self[index] end})
(i)("implies")(j)

如果implies = "implies",甚至可以缩短为(i)(implies)(j)

Hacky,“真正的”中缀表示法

如果中缀表示法至关重要,但您不能使用可用的元方法,因为它们有限且不可读,您可以使用更多柯里化和变通方法来使用其他元方法来创建看似可以改变您的函数的运算符(至少在语法上)使用“代理”元 table 而不是函数转换为中缀运算符。您可以使用任何您喜欢的运算符;只需确保它们在关联性和优先级方面满足您的需求即可:

local implies_right_hand_mt = {
    __mul = function(self, b)
        return _implies(self.a, b)
    end
}
local implies_left_hand = setmetatable({}, {
    __mul = function(a)
        return setmetatable({a = a}, implies_right_hand_mt)
    end
})
implies = implies_left_hand

在您的示例中,语法将是 i *implies* j"i *implies* j"(使用乘法运算符)。但是,您也可以使用所有其他运算符(比较运算符除外),包括其他算术运算符,因为 implies 不是数字而是 table,因此可能会覆盖数字元方法。

旁注

考虑使用布尔值而不是数字。您将获得两个优势:

  1. 布尔值不使用大多数元方法(尤其是所有算术和按位元方法);
  2. 逻辑运算符notandor有效;您不必使用按位运算符(尽管它们也可以正常工作)。