可以在Lua中模拟bind吗?

可以在Lua中模拟bind吗?,lua,Lua,给定一个带有一个参数的lua函数,是否可以将该参数绑定到一个固定值以获得一个没有参数的函数 更一般地说,如何将lua函数的某些输入参数绑定到某些值 是的,这几乎可以用任何具有函数作为一级值的语言来实现 function f1(a) return a+1 end function bind(a) return function() return f1(a) end end local f2 = bind(42) print(f2()) -- 43 这个特定的示例适用于特定的函数和

给定一个带有一个参数的lua函数,是否可以将该参数绑定到一个固定值以获得一个没有参数的函数


更一般地说,如何将lua函数的某些输入参数绑定到某些值

是的,这几乎可以用任何具有函数作为一级值的语言来实现

function f1(a)
   return a+1
end

function bind(a)
   return function() return f1(a) end
end

local f2 = bind(42)
print(f2())
-- 43

这个特定的示例适用于特定的函数和参数数量,但是可以很容易地扩展为使用任意函数/参数。

我刚刚创建了一个帮助函数来实现Boost::bind的功能:

  • 它处理占位符,以便能够替换任何位置参数
  • 它在任何地方都能处理零
用法:
function\u活页夹(基本函数、占位符格式、参数…)

  • base_函数(function):要包装的函数
  • 占位符\ U格式(字符串):表示参数的放置方式,每个字符表示一个参数
    • :表示包装器中的参数
    • A
      :表示活页夹中的参数
    • ~
      :表示包装器中所有挂起的参数
请参阅下面的示例以更好地理解

简单的例子: 您还可以使用内置功能: 你也可以制作复杂的东西: 面向对象方法 安装程序 要执行更多OO操作,可以使用调试库:

-- apply metatable to all function
debug.setmetatable(function()end, {
    __index = {
        bind = function_binder,
    },
})
用法 以下是功能代码: 它与Lua5.3完美配合


托管在此处:

您的意思是currying(返回函数的函数)?当然可以,只需从函数返回一个函数即可。请参阅。它与咖喱不同,因为它不需要对函数本身进行任何更改。Boost的绑定是我想要实现的一个很好的例子:@benno:那么Boost.bind在哪些方面不需要更改函数呢?它创建一个新的函数对象,将给定的参数转换为对旧的可调用对象的调用。这将有效地更改函数。类似函数bind(f,…)local args={…}返回函数(…)返回f(unpack(args),…)end。这将绑定任意数量的参数,并允许添加额外的参数。类似函数add(a,b)返回a+b end;add5=绑定(add,5);print(add5(6))@jpjacobs-
f(unpack(args),…)
仅使用数组的第一个元素
args
。我们需要构建一个新数组,作为两个数组
args
{…}
的串联,然后才能
解包它。
local debug_print = function_binder(print, "A~", "DEBUG:")
debug_print("some logs for debug")
-- => prints: DEBUG some logs for debug

-- '~' will put all following arguments:
debug_print("some", "logs", "for", "debug")
-- => prints: DEBUG some logs for debug
local function stuff(...)
    print("Args: ", ...)
end

local wrapper = function_binder(stuff, ".A..AA~", "two", "five", "six")
wrapper(1, 3, 4, 7, nil, 9)
-- => prints: 1 two 3 4 five six 7 nil 9
-- apply metatable to all function
debug.setmetatable(function()end, {
    __index = {
        bind = function_binder,
    },
})
local debug_print = print:bind("A~", "DEBUG:")
debug_print("add some log")
-- => prints: DEBUG: add some log
local function packed_args_append(packed, nb_insert, ...)
    nb_insert = nb_insert > 0 and nb_insert or select('#', ...)

    for i = 1, nb_insert do
        packed[packed.n + 1] = select(i, ...)
        packed.n = packed.n + 1
    end
end

-- replace table.unpack as it doesn't always handle nil values correctly..
local function unpacknil(packed)
    local nb_args = packed.n

    local function unpack_n(n)
        if n == nb_args then
            return packed[n]
        end
        return packed[n], unpack_n(n + 1)
    end
    return unpack_n(1)
end

function function_binder(self, placeholder_format, ...)
    local placeholders = table.pack(...)

    return function(...)
        local args = {n = 0}
        local arg_idx = 1
        local placeholder_idx = 1


        for c in placeholder_format:gmatch"." do
            if c == 'A' then
                packed_args_append(args, 1, placeholders[placeholder_idx])
                placeholder_idx = placeholder_idx + 1
            elseif c == '.' then
                packed_args_append(args, 1, select(arg_idx, ...))
                arg_idx = arg_idx + 1
            elseif c == '~' then
                packed_args_append(args, -1, select(arg_idx, ...))
                break
            end
        end
        --return self(table.unpack(args))
        return self(unpacknil(args))
    end
end