【问题标题】:Lua - rewriting coroutine recursion to tail-call recursionLua - 将协程递归重写为尾调用递归
【发布时间】:2017-12-01 12:33:01
【问题描述】:

我必须编写一个可以遍历嵌套表的迭代器。我用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

此代码返回我需要的内容:

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(...)),因为它只会返回一次。

所以我的问题是:如何将这个函数打包成可以并行调用的东西?或者换句话说:我可以通过返回值实现'yield'部分的功能,而不是将结果传递到全局变量中吗?

我尝试按照here 的模式使其成为一个对象,但我无法让它工作。

【问题讨论】:

    标签: recursion lua tail-recursion coroutine


    【解决方案1】:

    您可以将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
    

    【讨论】:

    • 无法在评论中找到答案? ;)
    • @PaulKulchenko - 是的,很不幸。 :-)
    猜你喜欢
    • 2020-09-16
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多