繁体   English   中英

无限深度和无限宽度玫瑰树的懒惰折叠到其边缘路径

[英]Lazy Folding of Infinite Depth & Infinite Breadth Rose Tree to its Edge Paths

这个问题包括将玫瑰树折叠成路径的代码折叠玫瑰树路径。 我正在尝试无限的玫瑰树,我发现所提供的解决方案并不足以在宽度和宽度上无限的玫瑰树上工作。

考虑像玫瑰树一样:

data Rose a = Rose a [Rose a] deriving (Show, Functor)

这是一棵有限的玫瑰树:

finiteTree = Rose "root" [ 
    Rose "a" [ 
        Rose "d" [], 
        Rose "e" []
    ], 
    Rose "b" [ 
        Rose "f" [] 
    ], 
    Rose "c" [] 
]

边路径列表的输出应为:

[["root","a","d"],["root","a","e"],["root","b","f"],["root","c"]]

这是两个维度中的无限玫瑰树:

infiniteRoseTree :: [[a]] -> Rose a
infiniteRoseTree ((root:_):breadthGens) = Rose root (infiniteRoseForest breadthGens)

infiniteRoseForest :: [[a]] -> [Rose a]
infiniteRoseForest (breadthGen:breadthGens) = [ Rose x (infiniteRoseForest breadthGens) | x <- breadthGen ]

infiniteTree = infiniteRoseTree depthIndexedBreadths where
    depthIndexedBreadths = iterate (map (+1)) [0..]

树看起来像这样(它只是一个摘录,有无限的深度和无限的宽度):

      0
      |
      |
    [1,2..]
    /  \
   /    \
  /      \
[2,3..]  [2,3..]

路径看起来像:

[[0,1,2..]..[0,2,2..]..] 

这是我最近的尝试(在GHCi上执行此操作会导致无限循环,没有流输出):

rosePathsLazy (Rose x []) = [[x]]
rosePathsLazy (Rose x children) = 
    concat [ map (x:) (rosePathsLazy child) | child <- children ]

rosePathsLazy infiniteTree

另一个答案中提供的解决方案也没有产生任何输出:

foldRose f z (Rose x []) = [f x z]
foldRose f z (Rose x ns) = [f x y | n <- ns, y <- foldRose f z n]

foldRose (:) [] infiniteTree

上述两种工作都适用于有限玫瑰树。

我尝试了很多变化,但我无法弄清楚边缘折叠操作是否对于无限的二维玫瑰树来说是懒惰的。 我觉得它与无限量的concat

由于输出是二维列表。 我可以同时运行具有深度限制或宽度限制或两者的二维take和项目!

任何帮助表示赞赏!


在回顾了这里的答案并思考了一下之后。 我又意识到,这是展开的,因为产生的名单是不可数无穷。 这是因为无限深度和宽度玫瑰树不是二维数据结构,而是无限维数据结构。 每个深度级别都赋予额外的维度。 换句话说,它有点等同于无限维矩阵,想象一个矩阵,其中每个场是另一个矩阵.ad-infinitum。 无限矩阵的基数是infinity ^ infinity ,已被证明(我认为)无穷无尽。 这意味着任何无限维数据结构在有用的意义上都不是真正可计算的。

要将此应用于玫瑰树,如果我们有无限深度,那么路径永远不会枚举玫瑰树的最左边。 就是这棵树:

      0
      |
      |
    [1,2..]
    /  \
   /    \
  /      \
[2,3..]  [2,3..]

会产生如下路径: [[0,1,2..], [0,1,2..], [0,1,2..]..] ,我们永远不会超过[0,1,2..]

或者换句话说,如果我们有一个包含ad-infinitum列表的列表。 我们也可以永远不会计算(枚举)它,因为代码会跳转到无限量的维度。

这也与实数无关也有一些关系。 在一个懒惰的无限实数列表中,它将无限地产生0.000..并且永远不会枚举过去。

我不确定如何形式化上述解释,但那是我的直觉。 (有关参考,请参阅: https//en.wikipedia.org/wiki/Uncountable_set )看到有人将https://en.wikipedia.org/wiki/Cantor's_diagonal_argument应用于此问题,这很酷。

本书似乎对此进行了扩展: https//books.google.com.au/books?id = OPFoJZeI8MEC&gt = PA140&lpg = PA140&div = haskell +uncountably+infinite&source=bl&ots=Z5hM-mFT6A&sig=ovzWV3AEO16M4scVPCDD-gyFgII&hl=en&sa=X&redir_esc= Y#v = onepage&q =哈斯克尔%20uncountably%20infinite&F =假

出于某种原因,dfeuer删除了他的答案,其中包括一个非常好的洞察力,只有一个轻微的,容易解决的问题。 下面我讨论他很好的见解,并修复容易解决的问题。

他的观点是,原来的代码挂原因是因为它并不明显concat任何参数列表中的元素都是非空。 既然我们可以证明这一点(在Haskell之外,用纸和笔),我们可以稍微欺骗一下来说服编译器它就是这样。

不幸的是, concat还不够好:如果你给concat一个像[[1..], foo]这样的列表,它永远不会从foo提取元素。 universe包的集合可以在这里帮助它的diagonal函数,它可以从所有子列表中绘制元素。

总之,这两个见解导致以下代码:

import Data.Tree
import Data.Universe.Helpers

paths (Node x []) = [[x]]
paths (Node x children) = map (x:) (p:ps) where
    p:ps = diagonal (map paths children)

如果我们定义一个特定的无限树:

infTree x = Node x [infTree (x+i) | i <- [1..]]

我们可以看看它在ghci中的表现如何:

> let v = paths (infTree 0)
> take 5 (head v)
[0,1,2,3,4]
> take 5 (map head v)
[0,0,0,0,0]

看起来不错! 当然,正如ErikR所观察到的,我们不能在这里拥有所有路径。 然而,给出的任何有限的前缀p通过一个无限路径的t ,存在一个有限索引paths t其元素与前缀开始p

不是一个完整的答案,但你可能会对这个关于如何编写Haskell的permutations函数的详细答案感兴趣,以便它可以在无限列表上运行:

这个列表在Haskell中的排列实现到底是做什么的?

更新

这是创建无限Rose树的更简单方法:

iRose x = Rose x [ iRose (x+i) | i <- [1..] ]

rindex (Rose a rs) [] = a
rindex (Rose _ rs) (x:xs) = rindex (rs !! x) xs

例子:

rindex (iRose 0) [0,1,2,3,4,5,6]     -- returns: 26
rindex infiniteTree [0,1,2,3,4,5,6]  -- returns: 13

无限深度

如果Rose树具有无限深度和非平凡宽度(> 1),则不能使用计数参数列出所有路径的算法 - 总路径数不可数。

有限深度和无限宽度

如果Rose树具有有限的深度,即使树具有无限宽度,路径的数量也是可数的,并且存在可以产生所有可能路径的算法。 观看此空间以获取更新。

ErikR解释了为什么你不能生成一个必须包含所有路径的列表,但是可以从左边懒洋洋地列出路径。 最简单的技巧,虽然是一个肮脏的技巧,但是要认识到结果永远不会是空的并且在Haskell上强制这个事实。

paths (Rose x []) = [[x]]
paths (Rose x children) = map (x :) (a : as)
  where
    a : as = concatMap paths children
    -- Note that we know here that children is non-empty, and therefore
    -- the result will not be empty.

为了制作非常无限的玫瑰树,请考虑

infTree labels = Rose labels (infForest labels)
infForest labels = [Rose labels' (infForest labels')
                      | labels' <- map (: labels) [0..]]

正如chi 指出的那样 ,虽然这种paths定义是有效的,但在某些情况下,它会永远地重复最左边的路径,而且永远不会再到达。 哎呀! 因此,为了给出有趣/有用的结果,有必要进行公平或对角遍历。

暂无
暂无

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

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