Search code examples
lualua-tableevaluationmetatablemeta-method

Currying operations in lua


This question has some reference to the question Defining logical operator implies in lua. The following code works fine.

local function _implies(a, b)
      if a == 1 and b == 0 then return 0 
        else return 1 end
    end
    
    local my_right = {
        __mul = function(self, b)
            return _implies(self.a, b)
        end
      }
      
      local _mt =  {
        __mul = function(a)
            return setmetatable({a=a}, my_right)
        end
    }
    
    local my_left={}
    setmetatable(my_left,_mt)
    imp = my_left
    local names={}
    
    
    for i = 0,1 do
       for j=0,1 do
         names.i=i;names.j=j
       print(i, j, names.i *imp* names.j)
      
       end
    end

The following code is similar to above code. It is for logical and. The question I want to ask is : Are both and_left and and_right are required in this case as well? Were they required because implies is not commutative? In other words, can the code be made somewhat efficient for defining logand?

    local function _and(a, b)
          if a == 1 and b == 1 then return 1 
            else return 0 end
    end
    
    local right_and = {
        __mul = function(self, b)
            return _and(self.a, b)
        end
      }
      
      local and_mt =  {
        __mul = function(a)
            return setmetatable({a=a}, right_and)
        end
    }
    
    local and_left={}
    setmetatable(and_left,and_mt)
   log_and = and_left
    local names={}
    
    
    for i = 0,1 do
       for j=0,1 do
 names.i=i;names.j=j
       print(i, j, names.i *log_and* names.j)
      
       end
end

Note: I know bitwise operator & is there but for some reasons, I don't want to use it.


Solution

  • Are both and_left and and_right are required

    They were introduced because there are two semantically different multiplications involved.

    But the code can be optimized.
    The version below does not create a new table on every multiplication.
    It also uses only one metatable instead of two.

    do
       local function _implies(a, b)
          if a == 1 and b == 0 then
             return 0
          else
             return 1
          end
       end
    
       local temp, imp = {}, {}
       local _mt =  {
          __mul = function(a, b)
             if b == imp then
                temp[1] = a
                return temp
             elseif a == temp then
                return _implies(temp[1], b)
             end
          end
       }
       setmetatable(temp, _mt)
       setmetatable(imp, _mt)
       _G.imp = imp
    end
    
    local names={}
    for i = 0, 1 do
       for j = 0, 1 do
          names.i=i
          names.j=j
          print(i, j, names.i *imp* names.j)
       end
    end