简体   繁体   English

Lua - 将coroutine递归重写为尾调用递归

[英]Lua - rewriting coroutine recursion to tail-call recursion

I have to write an iterator that can traverse nested tables. 我必须编写一个可以遍历嵌套表的迭代器。 I wrote one using coroutine . 我用coroutine写了一个。

It created an array of (path, value) pairs, eg {{key1, key2, key3}, value} meaning that to get value you got to do nested_table[key1][key2][key3] . 它创建了一个(路径,值)对的数组,例如{{key1, key2, key3}, value}意味着要获得value你必须做nested_table[key1][key2][key3]

Upon that I wrote find() , findall() , in() with ease, life was bright. 在那之后我轻松地写了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

Then I realized that the Lua environment I have to work with has coroutine blacklisted. 然后我意识到我必须使用的Lua环境已经将coroutine列入黑名单。 We can not use that. 我们不能使用它。 So I try to get the same functionality without 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

This code returns what I need: 此代码返回我需要的内容:

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]

But I still have a problem: I can not use a global variable, pool , this code is called paralleled. 但我还是有一个问题:我不能使用全局变量pool ,这个代码被称为并行。 And I can not do proper tail-call recursion ( return flatten(...) ) from a for cycle as it would return only once. 我不能从for循环中进行正确的尾调用递归( return flatten(...) ),因为它只返回一次。

So my question: how do I package this function into something that can be called in parallel? 所以我的问题是:如何将此函数打包成可以并行调用的函数? Or in other words: can I achieve what the 'yield' part does with a return value, instead of piping the results into a global variable? 换句话说:我可以实现'yield'部分对返回值的作用,而不是将结果传递给全局变量吗?

I tried to make it an object, following the patterns here , but I could not get it work. 我试图让它成为一个对象,遵循这里的模式,但我无法让它工作。

You can make pool variable 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, 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM