Pause iteration - lua

I have Lua table, t, which I iterate:
for k, v in pairs(t) do
b = false
my_func(v)
end
and want iteration to pause until b global variable changes to true
Is it possible is Lua?

Unless you're in a coroutine, there's no concept of a Lua variable changing value without your code doing it. So you would be pausing until something that can't possibly happen happens. Lua is inherently single-threaded.
As previously stated, you can use a coroutine to do this, but you'll have to modify your code accordingly:
function CoIterateTable(t)
for k, v in pairs(t) do
b = false
my_func(v)
while(b == false) do coroutine.yield() end
end
end
local co = coroutine.create(CoIterateTable)
assert(co.resume(t))
--Coroutine has exited. Possibly through a yield, possibly returned.
while(co.running()) do
--your processing between iterations.
assert(co.resume(t))
end
Note that changing the table referenced by t between iterations is not going to do something useful.

Related

Lua table.foreach missing

I used https://www.lua.org/cgi-bin/demo quite a lot to quickly hack together some scripts and test if they actually work. But today I stumpled across something that is very strange.
Testing this code
local t = {}
local threshold = 3
local counter = 0
t["1"] = true
t["2"] = true
t["3"] = false
t["4"] = true
table.foreach(t, print)
table.foreach(
t,
function(k,v)
if v then
counter = counter + 1
end
end
)
print(counter)
gave me this error message
input:9: attempt to call a nil value (field 'foreach')
so I tried running
for k,v in pairs(table) do
print(k,v)
end
resulting in this output
concat function: 0x42be90
remove function: 0x42bca0
sort function: 0x42ba50
move function: 0x42baf0
insert function: 0x42bda0
unpack function: 0x42b2a0
pack function: 0x42b3a0
Since it's about a year ago I last used this site to test my code I can't really tell when there was a change. Or if there was a change. I am very sure last time I used that site I used the table.foreach function. But now it does not work.
I also checked the changelog in case there was a change I missed but https://www.lua.org/versions.html does not show any change past June 2020 with version 5.4
May someone tell me where I messed up or what I am missing?
The error 'attempt to call a nil value (field 'foreach')' is indicating that the table.foreach() function is not defined. This error is likely caused by the fact that the table.foreach() function was removed in Lua 5.3.
In Lua 5.3, the equivalent method for iterating over a table is the pairs() function.
To fix this error you can replace the table.foreach with for k, v in pairs(t) do and replace the second table.foreach with for k, v in pairs(t) do
for k, v in pairs(t) do
print(k,v)
end
counter = 0
for k, v in pairs(t) do
if v then
counter = counter + 1
end
end
print(counter)

Trying to understand Custom Iterators

im trying to understand the iterators, in many examples I founf something like this:
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
function squares(iteratorMaxCount)
return square,iteratorMaxCount,0 // why not return square(iteratorMAxCount,0)????
end
for i,n in squares(3)
do
print(i,n)
end
First I dont understand the line I comment, and I dont find an easy example of how to do a Stateful Iterator and a Stateless iterator. Can anybody help me? thanks
From Lua Reference Manual 3.3.5:
A for statement like
for var_1, ···, var_n in explist do block end is equivalent to the code:
do
local f, s, var = explist
while true do
local var_1, ···, var_n = f(s, var)
if var_1 == nil then break end
var = var_1
block
end
end Note the following:
explist is evaluated only once. Its results are an iterator function,
a state, and an initial value for the first iterator variable. f, s,
and var are invisible variables. The names are here for explanatory
purposes only. You can use break to exit a for loop. The loop
variables var_i are local to the loop; you cannot use their values
after the for ends. If you need these values, then assign them to
other variables before breaking or exiting the loop.
So squares() has to return a function (square) a state (iteratorMaxCount) and an initial value (0) in order to work with a generic for loop.
Read the reference manual, Programming in Lua.

How do I retain the value of a for loop variable when the loop is over?

I'm trying to find something in a loop in Lua, and when I'm done I need to use the location I found.
for j = 1,100 do
<do some stuff>
if <some test> then
break
end
end
if j >= 100 then
return
end
Unfortunately, I get an error which suggests that after the for loop exits, the value of j is nil. How do I use the value that j ended at? Obviously I could create an extra variable and assign it right before I break, but that just seems wrong, and I've never seen another language set the loop variable to nil when the loop ends, so I'm wondering if there isn't a better way to accomplish this.
The loop variable is only visible inside the for loop block. You can get around this by creating another variable as suggested in PIL 4.3.4 Numeric For.
local index
for j=1,100 do
if j == 10 then
index = j
end
end
Alternatively, if you are a doing a common operation then using a function with an early return may be best.
function find(tbl, val)
for i, v in ipairs(tbl) do
if v == val then
return i
end
end
end

Lua nested coroutines

I am trying to use the redis-lua library within copas. It requires some patching.
One problem is that redis-lua defines some iterators as coroutines, but these iterators perform network operations that can yield.
So, coroutine.yield is used for two very different things: for the iterator, and for copas. As network calls are nested within iterators, network yields are intercepted by the coroutine.wrap of the iterator, instead of being intercepted by copas.
The example below shows the problem :
local function iterator ()
for i = 1, 2 do
if i == 2 then coroutine.yield () end -- network yield
coroutine.yield () -- iterator yield
end
end
local citerator = coroutine.wrap (iterator)
local function loop () -- use of the iterator within a copas thread
while citerator () do end
end
local cloop = coroutine.create (loop)
while coroutine.resume (cloop) do end -- same as copas loop, executes the cloop thread
Is there a "standard" solution to this problem, still allowing to use coroutines for iterators?
I was able to make a small example work by "tagging" the yields (see below), but it is incompatible with existing code. I can leave the copas code unmodified, but have to update iterators in redis-lua.
local function wrap (f, my_tag)
-- same as coroutine.wrap, but uses my_tag to yield again
local co = coroutine.create (f)
return function ()
local t = table.pack (coroutine.resume (co))
local code = t [1]
local tag = t [2]
table.remove (t, 1)
table.remove (t, 1)
if tag == nil then
return
elseif my_tag == tag then
return table.unpack (t)
else
coroutine.yield (tag, table.unpack (t))
end
end
end
local Iterator = {} -- tag for iterator yields
local Network = {} -- tag for network yields
local function iterator ()
for i = 1, 2 do
if i == 2 then coroutine.yield (Network, i) end
coroutine.yield (Iterator, i)
end
end
local citerator = wrap (iterator, Iterator)
local function loop ()
while citerator () do end
end
local cloop = wrap (loop, Network)
while cloop () do end
Is there a better solution?
Lua coroutine always yield to the last thread they were resumed from. The Copas socket functions expect to yield back to the Copas event loop, but instead they get stuck with the coroutine used to implement the redis-lua iterators. Unfortunately there isn't much you can do to fix that except changing the code of the redis-lua iterators. The reason why no one has done so yet is that until Lua 5.2 (LuaJIT can do it as well) it wasn't even possible to yield from an iterator function (the iterator yields in redis-lua work fine because they never leave the iterator function, but you cannot yield beyond the for loop like the Copas socket functions would try to do).
Your idea about using a tag value for distinguishing the iterator yields from the rest is good. You just have to make sure that you pass all yields not intended for the iterator function to the coroutine one level up, including any arguments/return values of coroutine.yield and coroutine.resume (the later is implicit when calling the coroutine.wraped function).
More specifically, if you have code like this in redis-lua:
-- ...
return coroutine.wrap( function()
-- ...
while true do
-- ...
coroutine.yield( some_values )
end
end )
You change it to:
-- ...
local co_func = coroutine.wrap( function()
-- ...
while true do
-- ...
coroutine.yield( ITERATOR_TAG, some_values ) -- mark all iterator yields
end
return ITERATOR_TAG -- returns are also intended for the iterator
end )
return function()
return pass_yields( co_func, co_func() ) -- initial resume of the iterator
end
The ITERATOR_TAG and the pass_yields function go somewhere near the top of redis.lua:
local ITERATOR_TAG = {} -- unique value to mark yields/returns
local function pass_yields( co_func, ... )
if ... == ITERATOR_TAG then -- yield (or return) intended for iterator?
return select( 2, ... ) -- strip the ITERATOR_TAG from results and return
else
-- pass other yields/resumes back and forth until we hit another iterator
-- yield (or return); using tail recursion here instead of a loop makes
-- handling vararg lists easier.
return pass_yields( co_func, co_func( coroutine.yield( ... ) ) )
end
end
AFAIK, the redis-lua developers are planning to tag another release by the end of the year, so they probably will be grateful for pull requests.
In your first example, you are using wrap(loop). I suppose this is copas' wrap, because there is no reference to copas in this code...
However, you are supposed to copas.wrap() a socket, but your loop is a function!
See copas documentation for a good introduction.

Functions in a Table - Lua

I have a table that has multiple functions in it. I'm trying to write a single function that will go through and use all the functions by passing random information into it.
Methods = {}
insert functions into Methods Table
function Methods:Multi() if #self > 0
then .........................
I'm guessing i need a loop that goes through the entire table but I can't do #self because i need it to do each function multiple times. Not sure how to pass in random info to the function either. Any help would be appreciated
Your problem doesn't seem to be all that specific - you're likely going to need to define exactly what you want to happen in more detail in order to be able to implement a program for it. (Sort of like if you told me "I need a program that calculates a number" - I'd probably respond "okay, what number do you want it to calculate?"
Things to consider:
Exactly how many times do you want to call each function? Will this be the same for each function? Will it vary?
If the number of calls varies, what should determine this?
How exactly do you want to determine what parameters are passed? Their types/count? Their values?
A very basic starting framework might look like this:
Methods = {}
-- Insert functions into Methods table
for _,func in ipairs(Methods) do
for i=1,5 do
func()
end
end
which would call each function 5 times, albeit w/o arguments.
I modified the above suggestion to
function CallFuncs(times, funcs, ...)
while (times > 0) do
for _, func in pairs(funcs) do
func(...)
end
times = times - 1
end
end
Example usage:
t = {
function( n ) print( n ) end,
function( n ) print( #n ) end,
}
CallFuncs( 2, t, 'foo' )
yields
foo
3
foo
3
Try this:
function CallFuncs(times, funcs, ...)
for i=1,times do
for _, func in pairs(funcs) do
if type(...) == "table" then func(unpack(...)) else func(...) end
end
end
end
Usage:
local t = {
function(n) print(n) end,
function(n) print(n+1) end,
function(n) print(n+2) end
}
CallFuncs(3, t, 2)
This assumes all the functions in the table have more or less the same arguments.
Info:
The ... you see is lua's syntax for variable arguments (these are packed into a table and used as the last argument to the function), and the unpack function takes a table and multi-returns a series of values.
If you are asking for something to call a list of functions, I just typed this very small module for you (if you can even call it that).
-- No guarantees whether this will work.
function ExecFunc (fnctn,nTimes,Threaded,...)
local to_call = function ()
fnctn(...)
end
for x = 1,nTimes do
if Threaded then
coroutine.resume(coroutine.create(to_call))
else
to_call()
end
end
end
function ExecFuncs (Async,...)
-- All parts of ... should be tables {function f, number t[, table args]}
local funcInfo = {...}
for _,funcThing in pairs(funcInfo) do
local a = funcThing.args
if a then
ExecFunc(funcThing.f,funcThing.t,Async,unpack(a))
else
ExecFunc(funcThing.f,funcThing.t,Async)
end
end
end
-- These don't check for argument validity,
-- so you should either be careful with the arguments
-- or call these in protected mode (with pcall).
If I wasted my time with that, it was fun anyway, but after typing it I reread your question... You want something to iterate through a list of functions and pass a random number to each one.
function ExecuteWithRandomValues (func_list,async)
assert(type(func_list) == "table","Expected table.")
local passbacks = {}
local threads
if async then
threads = {}
end
for _,func in pairs(func_list) do
assert(type(func) == "function","Value [" .. _ .. "] is not a function.")
local toCall = function ()
local rnd = math.random(-math.huge,math.huge)
local out = func(rnd)
passbacks[_] = {input = rnd, output = out}
end
if async then
table.insert(threads,coroutine.create(toCall))
else
toCall()
end
end
if async then
for _,thread in pairs(threads) do
coroutine.resume(thread)
end
for _,thread in pairs(threads) do
while coroutine.status(thread) ~= "dead" do
end
end
end
return passbacks
end
-- Again, no guarantees this thing is free of errors.
-- There are better ways to run and check the statuses
-- of asynchronous threads, but this is fairly convenient.

Resources