# Can this “syntax sweetener” be improved?

I have a Lua project that uses some syntax sugar described in DecoratorsAndDocstrings, near the bottom of the page. It looks like this:

random =
docstring[[Compute random number.]] ..
function(n)
return math.random(n)
end


Notice how the function definition is concatenated to the result of the function previous function call. I also have similar sugar like this:

something = foo.bar "Blah" { a = 1, b = 2 }


Basically, the idea is that instead of foo.bar taking two arguments (a string and a table), it only takes the first argument, and returns a function that finishes the operation (like a continuation). In the first example, instead of returning a function, we'd return a table with a __concat meta method.

I ended up with a handful of functions in my project that use syntax like this. The problem is:

• The code is not straightforward.
• It's difficult to document properly.
• Adding support for non-sugared calls compounds the previous two problems.

So, I had the idea to just write them as normal functions, and create a "sweeten" function that takes two arguments: a function to "sweeten," and the number of args it wants. It returns a wrapper for the function. If you call the wrapper with at least the required number of arguments, it will simply tail-call the wrapped function. If you call it with less arguments, it will instead return a sort of "continuation table" with both __call and __concat metamethods set up as wrappers to the wrapper -- calling them will invoke the wrapper again with the previous args and the new args.

local function sweeten(fn, argc)
local wrapper

argc = tonumber(argc) or 2

local function unpack_plus(t, i, ...)
i = i or 1
if i <= #t then
return t[i], unpack_plus(t, i + 1, ...)
else
return ...
end
end

local function resume(t, ...)
return wrapper(unpack_plus(t, 1, ...))
end

local meta = { __call = resume, __concat = resume }

wrapper = function(...)
if select('#', ...) >= argc then
return fn(...)
else
return setmetatable({...}, meta)
end
end

return wrapper
end


To test if out, you can do something like:

function foo(a, b, c) print(a, b, c) end
function sweet_foo = sweeten(foo, 3)
sweet_foo "qwe" "asd" "zxc" -- prints stuff


I feel like I should be able to simplify sweeten and still get the same result. I'd especially like to get rid of unpack_plus, but I can't see a way to do it. Any thoughts?