Haskell 收集有关现有树状数据的数据

Haskell 收集有关现有树状数据的数据,haskell,tree,traversal,Haskell,Tree,Traversal,假设我们有现有的树状数据,并且我们想添加关于每个节点深度的信息。我们怎样才能轻易做到这一点 Data Tree = Node Tree Tree | Leaf 对于每一个节点,我们都想知道它有多深。我们有来自外部模块的数据,所以我们有如上所示的信息。现实生活中的例子是外部HTML解析器,它只提供XML树,我们希望收集数据,例如每个节点包含多少超链接 函数式语言是为遍历树和收集数据而创建的,应该有一个简单的解决方案 显而易见的解决方案是创建并行结构。我们能做得更好吗?我从Chris Okasak

假设我们有现有的树状数据,并且我们想添加关于每个节点深度的信息。我们怎样才能轻易做到这一点

Data Tree = Node Tree Tree | Leaf
对于每一个节点,我们都想知道它有多深。我们有来自外部模块的数据,所以我们有如上所示的信息。现实生活中的例子是外部HTML解析器,它只提供XML树,我们希望收集数据,例如每个节点包含多少超链接

函数式语言是为遍历树和收集数据而创建的,应该有一个简单的解决方案


显而易见的解决方案是创建并行结构。我们能做得更好吗?

我从Chris Okasaki的精彩故事中学到的标准技巧是在每个节点缓存昂贵操作的结果。(也许这个技巧在冈崎的论文之前就知道了;我不知道。)您可以提供智能的构造函数来管理这些信息,这样构建树就不必很痛苦了。例如,当昂贵的操作是深度时,您可以编写:

module SizedTree (SizedTree, sizedTree, node, leaf, depth) where

data SizedTree = Node !Int SizedTree SizedTree | Leaf

node l r = Node (max (depth l) (depth r) + 1) l r
leaf = Leaf

depth (Node d _ _) = d
depth Leaf = 0

-- since we don't expose the constructors, we should
-- provide a replacement for pattern matching
sizedTree f v (Node _ l r) = f l r
sizedTree f v Leaf = v

构建
SizedTree
s会在每个节点上花费O(1)额外的工作(因此,将n节点
转换为
SizedTree
)是O(n)工作),但回报是检查
SizedTree
或任何子树的深度是O(1)操作。

您确实需要一些其他数据来存储这些
Int
s。将
树定义为

data Tree a = Node Tree a Tree | Leaf a
然后写一个函数

annDepth :: Tree a -> Tree (Int, a)
原始的
树()
,使用模式同义词可以恢复良好的构造函数


如果出于某种原因希望保留原始树,可以定义一个视图:

{-# LANGUAGE GADTs, DataKinds #-}

data Shape = SNode Shape Shape | SLeaf

data Tree a sh where
    Leaf :: a -> Tree a SLeaf
    Node :: Tree a lsh -> a -> Tree a rsh -> Tree a (SNode lsh rsh)
这样可以保证带注释的树与未注释的树具有相同的形状。但是,如果没有适当的依赖类型,这将无法正常工作



另外,看一看问题

标准解决方案是@DanielWagner建议的,只是扩展数据结构。这可能有点不方便,但可以解决:用于创建实例和使用的智能构造函数

也许会有帮助,尽管我自己还没有使用过这种方法。有一个基于此的图书馆


一种完全不同的方法是有效地记住您需要的值。我试图解决一个问题,其中一个解决方案是由图书馆提供的。请注意,这不是一种纯粹的功能性方法,因为库在内部基于对象标识,但接口是纯粹的,并且可以完美地用于此目的

。。。这不是函数式语言的重点。此外,您定义的数据结构也不是非常有用,因为它只跟踪树的形状,而不跟踪其中的数据。您可以想象其中也包含大数据,这只是简化。我不同意投票结果。关于Haskell中的树注释,有相当多的知识,答案可以有意义地涵盖其中。很好的解决方案。您想要
节点吗!Int…
?@ReinHenrichs这可能是个好主意。想想它被偷了!你不能偷免费赠送的东西。:)除非我不明白什么,否则我看不出这与答案有什么关系。它实际上并没有提供一种从现有结构中提取/变形数据的方法。@JKS从现有结构转换到此结构很容易<代码>转换::树->大小树;转化叶=叶;转换(节点l r)=节点l r