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
。