Lua - 将协程递归重写为尾调用递归
Lua - rewriting coroutine recursion to tail-call recursion
我必须编写一个可以遍历嵌套表的迭代器。我用 coroutine
.
写了一个
它创建了一个(路径,值)对数组,例如{{key1, key2, key3}, value}
意味着要获得 value
你必须做 nested_table[key1][key2][key3]
.
于是我轻松地写了find()
、findall()
、in()
,人生一片光明。
function table.extend(tbl, new_value)
local tbl = {table.unpack(tbl)}
table.insert(tbl, new_value)
return tbl
end
function iterate(tbl, parent)
local parent = parent or {}
if (type(tbl)=="table") then
for key, value in pairs(tbl) do
iterate(value, table.extend(parent, key))
end
end
coroutine.yield(parent, tbl)
end
function traverse(root)
return coroutine.wrap(iterate), root
end
然后我意识到我必须使用的 Lua 环境已被列入 coroutine
黑名单。我们不能使用那个。所以我尝试在没有 coroutine
的情况下获得相同的功能。
-- testdata
local pool = {}
test = {
['a'] = 1,
['b'] = {
['c'] = {2, 3},
['d'] = 'e'
}
}
-- tree traversal
function table.extend(tbl, element)
local copy = {table.unpack(tbl)}
table.insert(copy, element)
return copy
end
local function flatten(value, path)
path = path or {'root'}
pool[path] = value -- this is the 'yield'
if type(value) == 'table' then
for k,v in pairs(value) do
flatten(v, table.extend(path, k))
end
end
end
-- testing the traversal function
flatten(test)
for k, v in pairs(pool) do
if type(v) == 'table' then v = '[table]' end
print(table.concat(k, ' / ')..' -> '..v)
end
这段代码return是我需要的:
root -> [table]
root / b / c / 1 -> 2
root / b -> [table]
root / a -> 1
root / b / d -> e
root / b / c / 2 -> 3
root / b / c -> [table]
但是我还有一个问题:我不能使用全局变量,pool
,这段代码被称为并行。而且我无法从 for
循环中进行适当的尾调用递归 (return flatten(...)
),因为它只会 return 一次。
所以我的问题是:如何将这个函数打包成可以并行调用的东西?或者换句话说:我可以用 return 值实现 'yield' 部分的功能,而不是将结果传递到全局变量中吗?
我试图按照模式 here 将它变成一个对象,但我无法让它工作。
您可以将 pool
变量设置为本地变量:
test = {
['a'] = 1,
['b'] = {
['c'] = {2, 3},
['d'] = 'e'
}
}
-- tree traversal
function table.extend(tbl, element)
local copy = {table.unpack(tbl)}
table.insert(copy, element)
return copy
end
local function flatten(value, path, pool) -- third argument is the pool
path = path or {'root'}
pool = pool or {} -- initialize pool
pool[path] = value
if type(value) == 'table' then
for k,v in pairs(value) do
flatten(v, table.extend(path, k), pool) -- use pool in recursion
end
end
return pool -- return pool as function result
end
-- testing the traversal function
local pool = flatten(test)
for k, v in pairs(pool) do
if type(v) == 'table' then v = '[table]' end
print(table.concat(k, ' / ')..' -> '..v)
end
我必须编写一个可以遍历嵌套表的迭代器。我用 coroutine
.
它创建了一个(路径,值)对数组,例如{{key1, key2, key3}, value}
意味着要获得 value
你必须做 nested_table[key1][key2][key3]
.
于是我轻松地写了find()
、findall()
、in()
,人生一片光明。
function table.extend(tbl, new_value)
local tbl = {table.unpack(tbl)}
table.insert(tbl, new_value)
return tbl
end
function iterate(tbl, parent)
local parent = parent or {}
if (type(tbl)=="table") then
for key, value in pairs(tbl) do
iterate(value, table.extend(parent, key))
end
end
coroutine.yield(parent, tbl)
end
function traverse(root)
return coroutine.wrap(iterate), root
end
然后我意识到我必须使用的 Lua 环境已被列入 coroutine
黑名单。我们不能使用那个。所以我尝试在没有 coroutine
的情况下获得相同的功能。
-- testdata
local pool = {}
test = {
['a'] = 1,
['b'] = {
['c'] = {2, 3},
['d'] = 'e'
}
}
-- tree traversal
function table.extend(tbl, element)
local copy = {table.unpack(tbl)}
table.insert(copy, element)
return copy
end
local function flatten(value, path)
path = path or {'root'}
pool[path] = value -- this is the 'yield'
if type(value) == 'table' then
for k,v in pairs(value) do
flatten(v, table.extend(path, k))
end
end
end
-- testing the traversal function
flatten(test)
for k, v in pairs(pool) do
if type(v) == 'table' then v = '[table]' end
print(table.concat(k, ' / ')..' -> '..v)
end
这段代码return是我需要的:
root -> [table]
root / b / c / 1 -> 2
root / b -> [table]
root / a -> 1
root / b / d -> e
root / b / c / 2 -> 3
root / b / c -> [table]
但是我还有一个问题:我不能使用全局变量,pool
,这段代码被称为并行。而且我无法从 for
循环中进行适当的尾调用递归 (return flatten(...)
),因为它只会 return 一次。
所以我的问题是:如何将这个函数打包成可以并行调用的东西?或者换句话说:我可以用 return 值实现 'yield' 部分的功能,而不是将结果传递到全局变量中吗?
我试图按照模式 here 将它变成一个对象,但我无法让它工作。
您可以将 pool
变量设置为本地变量:
test = {
['a'] = 1,
['b'] = {
['c'] = {2, 3},
['d'] = 'e'
}
}
-- tree traversal
function table.extend(tbl, element)
local copy = {table.unpack(tbl)}
table.insert(copy, element)
return copy
end
local function flatten(value, path, pool) -- third argument is the pool
path = path or {'root'}
pool = pool or {} -- initialize pool
pool[path] = value
if type(value) == 'table' then
for k,v in pairs(value) do
flatten(v, table.extend(path, k), pool) -- use pool in recursion
end
end
return pool -- return pool as function result
end
-- testing the traversal function
local pool = flatten(test)
for k, v in pairs(pool) do
if type(v) == 'table' then v = '[table]' end
print(table.concat(k, ' / ')..' -> '..v)
end