If I want to write a function that takes varargs and returns a function that takes vargas I run into ambiguous ...
for example
function bind(func, ...) return function(...) func(..., ...) end end
First of all you're missing an end to close the bind function.
If you have ambiguities just resolve them by using different names.
function bind(func, ...)
return function(...) func(..., ...) end
end
If we test your code like that: bind(print, "a", "b", "c")(1,2,3)
you'll get the output:
1 1 2 3
If you have ... or any other name in a functions parameter list, that variable will be a local within the scope of that function. It will have priority over any other variable with the same name in a superior scope. So the ... in your anonymous function has nothing to do with the ... of function bind.
To resolve this problem you could simply do something like
function bind(func, ...)
local a = table.pack(...)
return function(...) func(table.unpack(a, 1, a.n), ...) end
end
Now calling bind(print, "a", "b", "c")(1,2,3) will output:
a 1 2 3
To find out what happened to b and c please read this section: https://www.lua.org/manual/5.3/manual.html#3.4.11
(and the rest of Lua's manual of course)
When a function is called, the list of arguments is adjusted to the length of the list of parameters, unless the function is a vararg function, which is indicated by three dots ('...') at the end of its parameter list. A vararg function does not adjust its argument list; instead, it collects all extra arguments and supplies them to the function through a vararg expression, which is also written as three dots. The value of this expression is a list of all actual extra arguments, similar to a function with multiple results. If a vararg expression is used inside another expression or in the middle of a list of expressions, then its return list is adjusted to one element. If the expression is used as the last element of a list of expressions, then no adjustment is made (unless that last expression is enclosed in parentheses).
So something like func(..., ...) will never work, even if ... were two different lists.
To avoid this you have to contatenate both argument lists.
function bind(func, ...)
local args1 = table.pack(...)
return function(...)
local args2 = table.pack(...)
for i = 1, args2.n do
args1[args1.n+i] = args2[i]
end
args1.n = args1.n + args2.n
func(table.unpack(args1, 1, args1.n))
end
end
bind(print, "a", nil, "c")(1,nil,3)
Which finally gives us the desired output:
a nil c 1 nil 3
But I am sure you can think of a nicer way to achieve your goal without concatenating various varargs.
You can try vararg library. Which also handles nil
in arguments.
va = require "vararg"
function bind(func, ...)
local args = va(...)
return function(...)
func(va.concat(args, va(...)))
end
end
bind(print, 1, nil, 2)(3, nil, 5)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With