在Lua中组合两个函数

我刚开始学习lua,所以我所问的问题可能是不可能的。

现在,我有一个接受函数的方法:

function adjust_focused_window(fn)
  local win = window.focusedwindow()
  local winframe = win:frame()
  local screenrect = win:screen():frame()
  local f, s = fn(winframe, screenrect)
  win:setframe(f)
end

我有几个接受这些框架和矩形的函数(只显示一个):

function full_height(winframe, screenrect)
   print ("called full_height for " .. tostring(winframe))
  local f = {
     x = winframe.x,
     y = screenrect.y,
     w = winframe.w,
     h = screenrect.h,
  }
  return f, screenrect
end

然后,我可以做到以下几点:

hotkey.bind(scmdalt, '-', function() adjust_focused_window(full_width) end)

现在,我如何将几个函数组成adjust_focused_window,而不改变它的定义。像这样的东西:

hotkey.bind(scmdalt, '=', function() adjust_focused_window(compose(full_width, full_height)) end)

其中compose2将返回一个接受与full_widthfull_height相同参数的函数,并在内部执行类似以下操作:

full_height(full_width(...))
点赞
用户111948
用户111948

你可以遍历传递的函数,连续使用前一个函数的结果调用链中的下一个函数。

function module._compose(...)
  local n = select('#', ...)
  local args = { n = n, ... }
  local currFn = nil

  for _, nextFn in ipairs(args) do
    if type(nextFn) == 'function' then
      if currFn == nil then
        currFn = nextFn
      else
        currFn = (function(prev, next)
          return function(...)
            return next(prev(...))
          end
        end)(currFn, nextFn)
      end
    end
  end

  return currFn
end

请注意以上使用即时调用函数表达式,允许重复使用函数变量而不会调用无限递归循环,在下面的代码中会发生这种情况:

function module._compose(...)
  local n = select('#', ...)
  local args = { n = n, ... }
  local currFn = nil

  for _, nextFn in ipairs(args) do
    if type(nextFn) == 'function' then
      if currFn == nil then
        currFn = nextFn
      else
        currFn = function(...)
          return nextFn(currFn(...)) -- 由于闭包,这将一直循环下去
        end
      end
    end
  end

  return currFn
end

尽管 Lua 不支持三元运算符,但可以使用短路求值 来删除内部的 if 语句:

function module.compose(...)
  local n = select('#', ...)
  local args = { n = n, ... }
  local currFn = nil

  for _, nextFn in ipairs(args) do
    if type(nextFn) == 'function' then
      currFn = currFn and (function(prev, next)
        return function(...)
          return next(prev(...))
        end
      end)(currFn, nextFn) or nextFn
    end
  end

  return currFn
end
2021-02-25 04:24:21