Working in lua, I have a table of key/value pairs
local fmtsToRun = {
name = function()
return configSubTable
end
}
Which could be 1 or more entries in length. I need to loop through each entry and run a subprocess (through some libuv C bindings).
With a normal for loop, the subprocess results from libuv return after the loop has finished running, leading to things showing up out of order. The result would be
Loop Start
Loop Entry 1
Job 1 starts
Loop Entry 2
Job 2 starts
Loop Ends
Job1 Returns
Job2 Returns
What I need to have is
Loop Start
Loop Entry 1
Job 1 starts
Job1 Returns
Loop Entry 2
Job 2 starts
Job2 Returns
Loop Ends
I've also tried writing my own version of pairs() to and using something like coroutines to handle the callbacks
for fmt, output in jobIterator(fmtsToRun) do
print('finished running', output)
end
local function jobIterator(tbl)
return coroutine.wrap(function()
local fmtConf, fmtName
fmtName, fmtConf = next(tbl, fmtName)
if nil~=fmtConf then
local conf = fmtConf()
local output = nil
-- wrapper util from Libuv library
local job = Job:new({
cmd = conf.cmd,
args = conf.args,
on_stdout = onStdout, -- process output
on_stderr = onStderr, -- process any error
on_exit = function()
coroutine.yield(fmtName, output)
end
})
job.send(conf.data)
end
end)
end
which leads to this error messages.
attempt to yield across C-call boundary
What would be the "right" way to wait for the job to finish and continue the loop while maintaining the correct order?
A better option was to manually control the flow and recursively call a function to step through the table one entry at a time.
local runner = {}
for _, output in pairs(fmtsToRun) do
table.insert(runner, output)
end
jobIterator(runner)
local function jobIterator(tbl)
local F = {}
function F.step()
if #tbl == 0 then
return
end
local current = table.remove(tbl, 1)
F.run(current)
end
function F.run(conf)
local output = nil
-- wrapper util from Libuv library
local job =
Job:new(
{
cmd = conf.cmd,
args = conf.args,
on_stdout = onStdout, -- process output
on_stderr = onStderr, -- process any error
on_exit = function()
-- do what you need with output
print(output)
F.step()
end
}
)
job.send(conf.data)
end
F.step()
end
Related
I'm trying to provide a curried lua function as method to call for autocomplete a command. However, it sometimes does nothing and sometimes fails with a memory segmentation error.
This is a minimal reproduction example:
Given this init.lua
vim.cmd(string.format([[set rtp=%s]], vim.fn.getcwd()))
local custom_complete = [[customlist,v:lua.require'split_later'.split_later('a b')]]
local options = { complete = custom_complete, desc = "Test to break", nargs = 1, force = true }
vim.api.nvim_create_user_command("Test", "echo <args>", options)
And this file called split_later under the correct lua/ subfolder:
local M = {}
function M.split_later(str)
print("called split")
return function()
return vim.fn.split(str)
end
end
return M
The idea is to have a generic utility that is able to produce auto-complete functions from lua, but it is not working as expected.
I found a workaround using a lookup table that stores the command name and then uses it, but I don't like it that much.
Lets take a look at this pseudo code example:
-- Wraps a function with given parameters inside a callback
-- Usefull for sending class methods as callbacks.
-- E.g. callback(object.method, object)
local function callback(func, ...)
return function(...)
func(..., ...)
end
end
How would I go about this?
I know there is unpack, but it would get swallowed by the second vararg:
local function callback(func, ...)
local args = { ... }
return function(...)
func(table.unpack(args), ...)
end
end
callback(print, "First", "Second")("Third") --> prints First Third
The only option I found so far, is to concat those together and then unpack it:
local function callback(func, ...)
local args1 = { ... }
return function(...)
local args2 = { ... }
local args = { }
for _, value in ipairs(args1) do
table.insert(args, value)
end
for _, value in ipairs(args2) do
table.insert(args, value)
end
func(table.unpack(args))
end
end
Is this the only solution, or could I do better?
What I would like to have is either a function, that concats two arrays together (which should be faster than those two for loops) and then use table.unpack on it, or make those varargs concat.
From the Lua 5.4 Reference Manual: 3.4 Expressions
If an expression is used as the last (or the only) element of a list
of expressions, then no adjustment is made (unless the expression is
enclosed in parentheses). In all other contexts, Lua adjusts the
result list to one element, either discarding all values except the
first one or adding a single nil if there are no values.
So the only way is to manually combine both lists to a single one befor you use them.
There are several ways to do this.
for i,v in ipairs(list2) do
table.insert(list1, v)
end
for i,v in ipairs(list2) do
list1[#list1+i] = v
end
table.move(list2, 1, #list2, #list1 + 1, list1)
I'm not sure what kind of problem you're actually trying to solve here.
If you want to access your object from its methods use self.
-- Wraps a function with given parameters inside a callback
-- Usefull for sending class methods as callbacks.
-- E.g. callback(object.method, object)
Usually you would do something like this:
local callback = function(params) object:method(params) end
callback(params)
Instead of
callback(print, "First", "Second")("Third")
You could do this
local callback = function (...) print("First", "Second", ...) end
callback("Third")
Edit ( opinonated )
My main goal is to use member functions as callbacks. However, I'd
like to keep it general. The advantage of a callback function is to
omit the function and end keyword. It's shorter and looks closer to
what it would look like, if there would be no need for a self
argument. So this: object.event = function(...) return
self:method(...) end would become to this: object.event =
callback(self.method, self) what would be even nicer, is this (sadly
not possible in lua) object.event = self:method
So instead of
RegisterCallback(function() obj:method() end)
You say it is easier to do this, so you don't have to write function end?
local function callback(func, ...)
local args1 = { ... }
return function(...)
local args2 = { ... }
local args = { }
for _, value in ipairs(args1) do
table.insert(args, value)
end
for _, value in ipairs(args2) do
table.insert(args, value)
end
func(table.unpack(args))
end
end
RegisterCallback(callback(obj.method, obj)())
Your approach is not going to work if any of the arguments is nil to begin with. And there is not a single advantage. You're just typing other words while increasing the chance of running into errors.
You can control the param order to optimize your function.
local function callback(func, ...)
local args = {...}
return function(...)
func(..., table.unpack(args))
end
end
callback(print, "second", "third")("first") -- prints first second third
Below is my code
require 'dpnn'
require 'cunn'
local deviceNumber = tonumber(os.getenv("CUDA_CARD_NR"))
cutorch.setDevice(deviceNumber)
local module = nn.Sequential():cuda()
module:add(nn.Linear(2,1):cuda())
module:add(nn.Sigmoid():cuda())
criterion = nn.BCECriterion():cuda() -- Binary Cross Entorpy Criteria
local targets = torch.CudaTensor(10):random(0,1)
local inputs = torch.CudaTensor(10,2):uniform(-1,1)
function trainEpoch(module,criterion,inputs,targets)
for i=1,inputs:size(1) do
local idx = math.random(1,inputs:size(1))
local input, target = inputs[idx], targets:narrow(1,idx,1)
-- forward
local output= module:forward(input)
local loss= criterion:forward(output,target)
-- backward
local gradOutput = criterion:backward(output,target)
module:zeroGradParameters()
local gradInput = module:backward(input,gradOutput)
--update
module:updateGradParameters(0.9) -- momentum
module:updateParameters(0.1) -- W = W -0.1*dL/dW
end
end
for i=1,100 do
trainEpoch(module,criterion,inputs,targets)
end
I am running above using the following command
CUDA_CARD_NR=1 luajit feedforwad.lua
It gives the following error
luajit: feedforwad.lua:13: attempt to call method 'random' (a nil value)
stack traceback:
feedforwad.lua:13: in main chunk
[C]: at 0x004064f0
I know that there is some error in the line
local targets = torch.CudaTensor(10):random(0,1)
But I am not able to figure out.
luajit: feedforwad.lua:13: attempt to call method 'random' (a nil
value)
Is not "some error" and you should not have problems to figure out what is wrong because the error message tells you exactly what is wrong.
You tried to call the a method named random which happens to be a nil value.
This means that there is no function with that name and therefor you can't call it.
According to the reference documentation (which you should have checked befor coming here) the function is actually named rand
I am sure I am missing something ridiculously simple, but I stared at this long enough to ask for your help. I am trying to write the simplest of all loggers, and when I'm trying to run it, it's not seeing the global variable (that I (think) I declare!). I am an "advanced" beginner in lua, so silly mistakes are not as common, but still do happen in my case. Please, tell me what I'm missing here!
Here's the logger code, and I'm testing it within the script....
local type, pairs, table, tostring, io, os, print = type, pairs, table, tostring, io, os, print
local file
LEVELS = {}
LEVELS ["ERROR"] = 0
LEVELS ["WARN"] = 1
LEVELS ["INFO"] = 2
LEVELS ["DEBUG"] = 3
print (LEVELS.WARN)
local level
function init (outputFile, debugLevel)
level = debugLevel
file = io.open(outputFile, "a")
local ret
if (file == nil) then ret = false else ret = true end
return ret
end
function warn (message)
if level ~= nil and level >= LEVELS.WARN and file ~= nil then
log(message)
end
end
function log (message)
local timestamp = os.date()
file:write(timestamp..' - '..message..'\n')
file:flush()
end
function deInit ()
file:close()
end
init ("testInsideLogger.lua", 3)
warn("HI")
deInit()
What I get in the output:
Print right after the declaration of LEVELS works, prints out 1.
But when I call the warn("HI") method, I get
attempt to index global 'LEVELS' (a nil value).
WHY???
Thank you so much for your help!
I want to exit execution of Lua script on some condition .
Example :
content = get_content()
if not content then
-- ( Here i want some kind of exit function )
next_content = get_content()
--example there can lot of further checks
Here I want that if I am not getting content my script suppose to terminate is should not go to check to next.
Use os.exit() or just return from some "main" function if your script is embedded.
os.exit()
kill process by sending a signal
do return end
stop execution
The two methods are not equal if you want to write and execute some luacode in the interpreter after stopping the execution by launching your program using the -i flag.
th -i main.lua
extract from the lua api doc :
For syntactic reasons, a break or return can appear only as the last statement of a block (in other words, as the last statement in your chunk or just before an end, an else, or an until). For instance, in the next example, break is the last statement of the then block.
local i = 1
while a[i] do
if a[i] == v then break end
i = i + 1
end
Usually, these are the places where we use these statements, because any other statement following them is unreachable. Sometimes, however, it may be useful to write a return (or a break) in the middle of a block; for instance, if you are debugging a function and want to avoid its execution. In such cases, you can use an explicit do block around the statement:
function foo ()
return --<< SYNTAX ERROR
-- `return' is the last statement in the next block
do return end -- OK
... -- statements not reached
end
In lua 5.2.0-beta-rc1+, you can add a label at the end of your code called ::exit:: or something of the like, and then whenever you need to exit the program just call it like this:
goto exit