![](/img/trans.png)
[英]How does Traversable use the fact that it subclasses both Foldable and Functor?
[英]how to use traversable on a tree
我试图了解如何使用Traversable遍历我的树数据结构。 我有这棵丑陋的树(实际上是森林),看起来像这样:
data ParseTree a = Leaf a | Node a (ParseTree a) (ParseTree a) | MultiNode a [ParseTree a]
deriving (Show, Functor, F.Foldable, T.Traversable)
t = Node S
(Node NP (Leaf DP) (Leaf NP))
(MultiNode VP
[Node VP (Node VP (Leaf VP) (Leaf PP)) (Node NP (Leaf DP) (Leaf NP)),
Node VP (Leaf VP) (Node PP (Leaf PP) (Node NP (Leaf DP) (Leaf NP)))]
)
我想找到多节点,这样就可以替换构建新树,在多节点中的每一项都可以建立一棵。
对我来说编写这样的函数很容易
findmulti :: ParseTree a -> [ParseTree a]
findmulti (Leaf a) = []
findmulti (Node a left right) = findmulti left ++ findmulti right
findmulti (MultiNode a lst) = [ (MultiNode a lst) ]
但是我认为我应该能够使用导线遍历并找到适合我的项目。 如果我做
traverse print t
我只得到最后的值:
S NP DP NP VP VP VP VP PP ...
但是我实际上希望遍历在多节点处停止。 如何控制遍历的深度? 还是因为Traversable和朋友对容器不了解而不可能?
最终,我想衍生出也可以替换多节点的镜头,但现在我只是想了解可遍历的工作原理。 我什至在使用正确的工具来完成工作?
构建一个Traversal'
任意对象的Traversal'
是相当容易的,尽管此功能比Data.Traversable
允许的泛泛得多, 因为 Traversal
必须只访问和精确地包含元素。
首先,让我们检查traverse
的签名
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
我喜欢将第一个参数称为“注入”功能。 Traversal
“访问”到Applicative
f
的所有内容。 在这种情况下,我们想访问MultiNode
因此我们可以专门化此类型。
multinodes :: Applicative f => (ParseTree a -> f (ParseTree a)) -> ParseTree a -> (f (ParseTree a))
要么
multinodes :: Traversal' (ParseTree a) (ParseTree a)
现在让我们考虑一下定义。 同样,目标是注入每个MultiNode
。
-- No multinodes here, so we use `pure` so as to inject nothing at all
multinodes inj l@Leaf{} = pure l
-- Here's a multinode, so we'll visit it with the injection function
multinodes inj m@Multinode{} = inj m
-- And we need to neither reject (thus stopping the traversal)
-- nor inject a branch. Instead, we continue the traversal deeper
multinodes inj (Node a l r) =
(\l' r' -> Node a l' r') <$> multinodes inj l
<*> multinodes inj r
这是我们的Traversal'
。
>>> t ^.. multinodes
[MultiNode VP [Node VP (Node VP (Leaf VP) (Leaf PP)) (Node NP (Leaf DP) (Leaf NP)),Node VP (Leaf VP) (Node PP (Leaf PP) (Node NP (Leaf DP) (Leaf NP)))]]
这段代码并不比为findmulti
编写的代码短—实际上,它只不过是展开的findMulti . traverse
findMulti . traverse
,但它立即与其他lens
组合器兼容,并演示了通过瞄准目标所需内部结构的类型提供Applicative
的一般方法。 只需编写一次Traversal'
将是对MultiNode
进行几乎任何访问的通用工具。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.