Lua variable length function arguments are nil - lua

I am trying to write a curry function in lua 5.2. My code looks like this:
function add(a, b)
return a + b
end
function curry(func, value)
return (function (...)
return func(value, table.unpack(arg))
end)
end
add2 = curry(add, 2)
print(add2(3))
The parameter arg however does not contain the value passed into the add2 function.
When I try and run the example from the Lua documentation it errors because arg is nil.
printResult = ""
function print (...)
for i,v in ipairs(arg) do -- arg is nil
printResult = printResult .. tostring(v) .. "\t"
end
printResult = printResult .. "\n"
end
How can I use variable length functions in 5.2 if this is not working?
Edit:
As user #siffiejoe has pointed out, my function here is just doing partial application, not proper currying. Here is my implementation of a proper curry function in lua using the error fix from the accepted answer.
function curry(func, params)
return (function (...)
local args = params or {}
if #args + #{...} == debug.getinfo(func).nparams then
local args = {table.unpack(args)}
for _,v in ipairs({...}) do
table.insert(args, v)
end
return func(table.unpack(args))
else
local args = {table.unpack(args)}
for _,v in ipairs({...}) do
table.insert(args, v)
end
return curry(func, args)
end
end)
end
Feel free to suggest changes and add test cases here

Since Lua 5.1, arg in this context has been replaced by ... (except that the latter is a list instead of a table).
So, table.unpack(arg) should be just ....
See Breaking Changes. The Lua Reference manuals are very good and this section in particular is highly useful.

Related

I'm getting the error "attempt to index local self (a number value)

require 'class'
Paddle=class{}
function Paddle:init(x,y,width,height)
self.x=x
self.y=y
self.width=width
self.height=height
self.dy=0
end function Paddle:update(dt)
if self.dy < 0 then
self.y = math.max(`enter code here`0, self.y + self.dy * dt)
else
self.y=math.min(VIRTUAL_HEIGHT,-self.height,self.y+self.dy*dt)
end
end
function Paddle:render()
love.graphics.rectangle('fill',self.x,self.y,self.width,self.height)
end
I am following the course CS50 lecture 0 pong update 5, and the same code is working for the teacher. I don't know why this is happening neither understand the problem because it makes no sense. If you want, here's 'class'. This problem isn't happening in the other class I made called 'ball' which does exactly the same thing. I also defined self.dy, and it does have a value "0" so I don't know why it does that error and what that error means.
local function include_helper(to, from, seen)
if from == nil then
return to
elseif type(from) ~= 'table' then
return from
elseif seen[from] then
return seen[from]
end
seen[from] = to
for k,v in pairs(from) do
k = include_helper({}, k, seen) -- keys might also be tables
if to[k] == nil then
to[k] = include_helper({}, v, seen)
end
end
return to
end
-- deeply copies `other' into `class'. keys in `other' that are already
-- defined in `class' are omitted
local function include(class, other)
return include_helper(class, other, {})
end
-- returns a deep copy of `other'
local function clone(other)
return setmetatable(include({}, other), getmetatable(other))
end
local function new(class)
-- mixins
class = class or {} -- class can be nil
local inc = class.__includes or {}
if getmetatable(inc) then inc = {inc} end
for _, other in ipairs(inc) do
if type(other) == "string" then
other = _G[other]
end
include(class, other)
end
-- class implementation
class.__index = class
class.init = class.init or class[1] or function() end
class.include = class.include or include
class.clone = class.clone or clone
-- constructor call
return setmetatable(class, {__call = function(c, ...)
local o = setmetatable({}, c)
o:init(...)
return o
end})
end
-- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons).
if class_commons ~= false and not common then
common = {}
function common.class(name, prototype, parent)
return new{__includes = {prototype, parent}}
end
function common.instance(class, ...)
return class(...)
end
end
-- the module
return setmetatable({new = new, include = include, clone = clone},
{__call = function(_,...) return new(...) end})
So this is the part where I call the update function, which is what someone said might be the error
function love.update(dt)
if love.keyboard.isDown('w') then
player1.dy=-PADDLE_SPEED
elseif love.keyboard.isDown('s') then
player1.dy=PADDLE_SPEED
else
player1.dy=0
end
if love.keyboard.isDown('up') then
player2.dy=-PADDLE_SPEED
elseif love.keyboard.isDown('down') then
player2.dy=PADDLE_SPEED
else
player2.dy=0
end
if gameState=='play' then
ball.update(dt)
end
player1.update(dt)
player2.update(dt)
This error is pretty clear on what you're doing wrong.
You're indexing local self, a number value.
That means that somewhere you're doing something like self.dy where self is not a table but a number and using the index operator . on numbers is not allowed as it does not make any sense.
The question is why self is not a table.
function myTable:myFunction() end
is short (syntactic sugar) for
function myTable.myFunction(self) end
and the function call
myTable:myFunction() is short for myTable.myFunction(myTable)
Please refer to the Lua manual.
Function Calls
Function Definitions
Find a function in your code that is defined with : and called with . and gets a number as first argument during that call.
That way a number ends up where you expect self.
I guess the error is in the main.lua which you did not provide.
There you have several calls to Paddle:update(dt). Writing myPaddle.update(dt) would cause that error for example. But I can't tell for sure as you did not provide your code.
But that it works for the teacher, but not for you is usually because you do something different/wrong.
Edit:
As you've provided more code I can tell for sure that the observed error is caused by
ball.update(dt)
player1.update(dt)
player2.update(dt)
This will put dt a number value, where the function expects self, the table ball.
replace it by
ball.update(ball, dt) or ball:update(dt)
player1.update(player1, dt) or player1:update(dt)
player2.update(player2, dt) or player2:update(dt)

Variable Number of Arguments table

In lua I'm using someone elses function that takes variable number of arguments. What I would like to be able to do is build the argument list via loop. Is this possible?
Example function:
printResult = ""
function print (...)
for i,v in ipairs(arg) do
printResult = printResult .. tostring(v) .. "\t"
end
printResult = printResult .. "\n"
end
I tried
print({"test","test2"})
But that just passes one argument (the table) to the function
You are looking for the table.unpack function. You can build the arguments to the vararg function you want to call in a table. Calling table.unpack on the table will expand the table into an argument list. Like so,
args = {}
for i = 1, 4 do
args[#args+1] = i * i * math.pi
end
print(table.unpack(args))
Also, you will need in the print function you posted to gather all those arguments into the arg list that you are using...
function print (...)
printResult = ""
arg = {...}
for i,v in ipairs(arg) do
printResult = printResult .. tostring(v) .. "\t"
end
printResult = printResult .. "\n"
return printResult
end
Finally, there is already a way to accomplish what you are trying to do using table.concat.
function print(...)
return table.concat({...}, "\t").."\n"
end

How do we change the way print displays a table

Assuming I have a piece of code such as the following
aTable = {aValue=1}
aTable_mt = {}
print(aTable)
What must I do to make Lua print something like aTable current aValue = 1 as opposed to table: 0x01ab1d2.
So far I've tried setting the __tostring metamethod but that doesn't seem to be invoked by print. Is there some metamethod I've been missing or does the answer have nothing to do with metamethods?
__tostring works:
aTable = {aValue=1}
local mt = {__tostring = function(t)
local result = ''
for k, v in pairs(t) do
result = result .. tostring(k) .. ' ' .. tostring(v) .. ''
end
return result
end}
setmetatable(aTable, mt)
print(aTable)
This prints aValue 1 (with one extra whitespace, remove it in real code). The aTable part is not available, because aTable is a variable that references the table, not the content of the table itself.
I'm not sure how you set the metamethod, but the following code prints "stringified" for me:
local aTable = {a = 1, b = 2}
setmetatable(aTable, {__tostring = function() return "stringified" end})
print(aTable)
If you want lua to generally print all tables human readable, you could
hook up/overwrite the print function:
local orig_print = print
print = function(...)
local args = {...}
for i,arg in ipairs(args) do
if type(arg) == 'table' then
args[i] = serialize(arg)
end
end
orig_print(table.unpack(args))
end
serialize could be serpent or some other lib from here
Note that this must be done before any other module/script is loaded.

how to call variant arguments method with unpack

I am trying to run a redis lua mock project to test my redis lua code. but obviously, there are bugs in the redis-mock project.
When I call redis.call('hget', 'foo', 'bar') in my test code, the redis mock throw an assert error at hash.lua#22 which is call from RedisLua.lua#20
-- RedisLua.lua
local call = function(self)
return (function(cmd, ...)
cmd = string.lower(cmd)
local arg = {...}
local ret = self.db[cmd](self.db, unpack(arg)) -- line 20
if self.RedisLua_VERBOSE then
print(cmd .. "( " .. table.concat(arg, " ") .. " ) === ".. tostring(ret))
end
return ret
end)
end
-- hash.lua
function RedisDb:hget(self,k,k2)
assert((type(k2) == "string")) -- # line 22
local x = RedisDb.xgetr(self,k,"hash")
return x[k2]
end
After trace, I found, the self is 'foo', the k is 'bar' and the k2 is actually nil, How can I fix this bug, the k should be foo, and the k2 should be 'bar'
I think you need to call redis:call('hget', 'foo', 'bar') or equivalently redis.call(redis,'hget','foo','bar'), rather than redis.call('hget', 'foo', 'bar').
Answer my own question.
When define as :, no self need.
-- hash.lua
function RedisDb:hget(self,k,k2)
assert((type(k2) == "string")) -- # line 22
local x = RedisDb.xgetr(self,k,"hash")
return x[k2]
end
change to
-- hash.lua
function RedisDb:hget(k,k2)
assert((type(k2) == "string")) -- # line 22
local x = RedisDb:xgetr(k,"hash")
return x[k2]
end

How does the __call metamethod in Lua 5.1 actually work?

I'm trying, as an exercise, to make a set implementation in Lua. Specifically I want to take the simplistic set implementation of Pil2 11.5 and grow it up to include the ability to insert values, delete values, etc.
Now the obvious way to do this (and the way that works) is this:
Set = {}
function Set.new(l)
local s = {}
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.insert(s, v)
s[v] = true
end
ts = Set.new {1,2,3,4,5}
Set.insert(ts, 5)
Set.insert(ts, 6)
for k in pairs(ts) do
print(k)
end
As expected I get the numbers 1 through 6 printed out. But those calls to Set.insert(s, value) are really rather ugly. I'd much rather be able to call something like ts:insert(value).
My first attempt at a solution to this looked like this:
Set = {}
function Set.new(l)
local s = {
insert = function(t, v)
t[v] = true
end
}
for _, v in ipairs(l) do
s[v] = true
end
return s
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
for k in pairs(ts) do
print(k)
end
This works mostly fine until you see what comes out of it:
1
2
3
4
5
6
insert
Very obviously the insert function, which is a member of the set table, is being displayed. Not only is this even uglier than the original Set.insert(s, v) problem, it's also prone to some serious trouble (like what happens if "insert" is a valid key someone is trying to enter?). It's time to hit the books again. What happens if I try this instead?:
Set = {}
function Set.new(l)
local s = {}
setmetatable(s, {__call = Set.call})
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.call(f)
return Set[f]
end
function Set.insert(t, v)
t[v] = true
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
for k in pairs(ts) do
print(k)
end
Now the way I'm reading this code is:
When I call ts:insert(5), the fact that insert doesn't exist to be called means that the ts metatable is going to be searched for "__call".
The ts metatable's "__call" key returns Set.call.
Now Set.call is called with the name insert which causes it to return the Set.insert function.
Set.insert(ts, 5) is called.
What's really happening is this:
lua: xasm.lua:26: attempt to call method 'insert' (a nil value)
stack traceback:
xasm.lua:26: in main chunk
[C]: ?
And at this point I'm stumped. I have absolutely no idea where to go from here. I hacked around for an hour with varying degrees of increasingly desperate variations on this code but the end result is that I have nothing that works. What undoubtedly obvious thing am I overlooking at this point?
Now the way I'm reading this code is:
When I call ts:insert(5), the fact that insert doesn't exist to be called means that the ts metatable is going to be searched for "__call".
There's your problem. The __call metamethod is consulted when the table itself is called (ie, as a function):
local ts = {}
local mt = {}
function mt.__call(...)
print("Table called!", ...)
end
setmetatable(ts, mt)
ts() --> prints "Table called!"
ts(5) --> prints "Table called!" and 5
ts"String construct-call" --> prints "Table called!" and "String construct-call"
Object-oriented colon-calls in Lua such as this:
ts:insert(5)
are merely syntactic sugar for
ts.insert(ts,5)
which is itself syntactic sugar for
ts["insert"](ts,5)
As such, the action that is being taken on ts is not a call, but an index (the result of ts["insert"] being what is called), which is governed by the __index metamethod.
The __index metamethod can be a table for the simple case where you want indexing to "fall back" to another table (note that it is the value of the __index key in the metatable that gets indexed and not the metatable itself):
local fallback = {example = 5}
local mt = {__index = fallback}
local ts = setmetatable({}, mt)
print(ts.example) --> prints 5
The __index metamethod as a function works similarly to the signature you expected with Set.call, except that it passes the table being indexed before the key:
local ff = {}
local mt = {}
function ff.example(...)
print("Example called!",...)
end
function mt.__index(s,k)
print("Indexing table named:", s.name)
return ff[k]
end
local ts = {name = "Bob"}
setmetatable(ts, mt)
ts.example(5) --> prints "Indexing table named:" and "Bob",
--> then on the next line "Example called!" and 5
For more information on metatables, consult the manual.
You said:
Now the way I'm reading this code is:
When I call ts:insert(5), the fact that insert doesn't
exist to be called means that the ts metatable is going
to be searched for "__call".
The ts metatable's "__call" key returns Set.call.
Now Set.call is called with the name insert which causes
it to return the Set.insert function.
Set.insert(ts, 5) is called.
No, what happens is this:
When insert isn't found directly in the ts object, Lua looks for __index in its metatable.
If it is there and it is a table, Lua will search for insert there.
If it is there and it is a function, it will call it with the original table (ts in this case) and the key being searched for (insert).
If it isn't there, which is the case, it is considered nil.
The error you're having is because you don't have __index set in your metatable, so you are effectively calling a nil value.
This can be solved by pointing __index to some table, namely Set, if you're going to store your methods there.
As for __call, it is used for when you call the object as a function. Ie:
Set = {}
function Set.new(l)
local s = {}
setmetatable(s, {__index=Set, __call=Set.call})
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.call(s, f)
-- Calls a function for every element in the set
for k in pairs(s) do
f(k)
end
end
function Set.insert(t, v)
t[v] = true
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
ts(print) -- Calls getmetatable(ts).__call(ts, print),
-- which means Set.call(ts, print)
-- The way __call and __index are set,
-- this is equivalent to the line above
ts:call(print)
Set = {}
function Set.new(l)
local s = {}
setmetatable(s, {__index=Set})
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.call(f)
return Set[f]
end
function Set.insert(t, v)
t[v] = true
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
for k in pairs(ts) do
print(k)
end
I modified your first version and this version would offer the features I think you are looking for.
Set = {}
Set.__index = Set
function Set:new(collection)
local o = {}
for _, v in ipairs(collection) do
o[v] = true
end
setmetatable(o, self)
return o
end
function Set:insert(v)
self[v] = true
end
set = Set:new({1,2,3,4,5})
print(set[1]) --> true
print(set[10]) --> nil
set:insert(10)
print(set[10]) --> true

Resources