As stated in the basic examples, you can have variable bound arguments and the variable argument list (...
). You can use this fact to recursively pull apart a list as you would in other languages (like Haskell). Below is an implementation of foldr()
that takes advantage of that. Each recursive call binds the head of the vararg list to x
, and passes the rest of the list to a recursive call. This destructures the list until there is only one argument (select('#', ...) == 0
). After that, each value is applied to the function argument f
with the previously computed result.
function foldr(f, ...)
if select('#', ...) < 2 then return ... end
local function helper(x, ...)
if select('#', ...) == 0 then
return x
end
return f(x, helper(...))
end
return helper(...)
end
function sum(a, b)
return a + b
end
foldr(sum, 1, 2, 3, 4)
--> 10
You can find other function definitions that leverage this programming style here in Issue #3 through Issue #8.
Lua's sole idiomatic data structure is the table. The table length operator is undefined if there are nil
s located anywhere in a sequence. Unlike tables, the vararg list respects explicit nil
s as stated in the basic examples and the remarks section (please read that section if you haven't yet). With little work the vararg list can perform every operation a table can besides mutation. This makes the vararg list a good candidate for implementing immutable tuples.
function tuple(...)
-- packages a vararg list into an easily passable value
local co = coroutine.wrap(function(...)
coroutine.yield()
while true do
coroutine.yield(...)
end
end)
co(...)
return co
end
local t = tuple((function() return 1, 2, nil, 4, 5 end)())
print(t()) --> 1 2 nil 4 5 | easily unpack for multiple args
local a, b, d = t() --> a = 1, b = 2, c = nil | destructure the tuple
print((select(4, t()))) --> 4 | index the tuple
print(select('#', t())) --> 5 | find the tuple arity (nil respecting)
local function change_index(tpl, i, v)
-- sets a value at an index in a tuple (non-mutating)
local function helper(n, x, ...)
if select('#', ...) == 0 then
if n == i then
return v
else
return x
end
else
if n == i then
return v, helper(n+1, ...)
else
return x, helper(n+1, ...)
end
end
end
return tuple(helper(1, tpl()))
end
local n = change_index(t, 3, 3)
print(t()) --> 1 2 nil 4 5
print(n()) --> 1 2 3 4 5
The main difference between what's above and tables is that tables are mutable and have pointer semantics, where the tuple does not have those properties. Additionally, tuples can hold explicit nil
s and have a never-undefined length operation.