Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using multiple parentheses when calling a function in lua

I've been learning currying in Lua and came across the following code:

function addup(x)
  local sum = 0
  local function f(n)
    if type(n) == "number" then
      sum = sum + n
      return f
    else
      return sum
    end
  end
  return f(x)
end

print(addup (1) (2) (3) ())  --> 6
print(addup (4) (5) (6) ())  --> 15

I assume that the (1) (2) (3) () part means that the values are passed to the function in succession rather than simultaneously. My problem is that I can't quite figure out how exactly these values are passed and how the function manipulates them. So the first value goes to x, but what happens to the second? Is it passed as n into the inner function? Then where goes the third one?

My other problem is with the line:

return f

Here a function returns itself without any value or even parentheses. I know that you can pass in a string or a table to a function omitting the parentheses but it is not the case here. So what's going on?

I looked in the manuals but didn't find anything on either of these features. I'd really appreciate an explanation or a link to a manual that covers this in detail. Thanks.

Update: link to the tutorial I referred to - http://lua-users.org/wiki/CurriedLua

As it was pointed out in one of the anwsers, there is no (x)(y) syntax in lua. What it is, is a series of function calls. This wasn't actually mentioned in the tutorial but was my assumption which turned out to be wrong, so I edited this bit out.

The issue is solved. Thank you for all your answers, they were very helpful.

like image 601
Furniture Avatar asked Aug 14 '26 06:08

Furniture


2 Answers

There is no (x)(y) syntax in Lua. That's why you don't find anything in the manual. (x)(y) on its own will cause a syntax error

addup (1) (2) (3) () is a sequence of function calls. To understand this you have to carefully read addup's code and realize that a function call is nothing but a function value followed by the call operator and that functions are just values that you can return as any other type.

This expression is evaluated from left to right.

The call operator () operates on the value to its left. So first we evaluate addup(1) which calls the global function addup.

addup defines a local number value local sum = 0 and a local function value f.

local function f(n)
    if type(n) == "number" then
      sum = sum + n
      return f
    else
      return sum
    end
  end

and then returns the return value of that function called with addup's argument x

return f(x)

sum is an upvalue to f, that's a value that was in scope where f was defined. so every time you call f it has access to sum.

So n becomes x in function f. As n is a number value f will add n to sum and return a itself f.

So addup(1) evaluates to a reference to f, a function value with the upvalue sum == 1.

Now we have this returned function value to the left of (2) which is another function call to f. This time n is 2. Again it is a number so it will be added to sum and f will return itself again.

Now f is called with (3). Same as above.

Finally f is called with (). This time n is nil and f returns sum. So addup (1) (2) (3) () ultimately evaluates to 6 befor it is handed to print.

Not sure where you got that example from but doesn't make too much sense to me. There are simpler ways to explain upvalues and closures. Code like that is unecessarily hard to read.

like image 103
Piglet Avatar answered Aug 17 '26 13:08

Piglet


something like this, by analogy:

local _L = {}
function addup(x)
  local sum = 0
  _L["f"] = function (n)
    if type(n) == "number" then
      sum = sum + n
      return _L["f"]
    else
      return sum
    end
  end
  return _L["f"](x)
end

print(addup (1) (2) (3) ())  --> 6
print(addup (4) (5) (6) ())  --> 15

"return f" - returns a reference to a function inside the local namespace, which is just a table.

like image 35
Mike V. Avatar answered Aug 17 '26 12:08

Mike V.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!