如何使用 lens 折叠 XML 元素的节点?
How do I fold nodes of an XML element using lens?
我正在使用 xml-lens 包来处理 XML。
给定一个 Element
,我想对其 elementNode :: [Node]
字段执行类似 concatMap
的计算。具体来说,满足某些条件的 NodeElement
应该产生更多的 NodeElement
s,而所有其他情况(NodeElement
s 的其余部分和其他 Node
构造函数)应该产生一个单例列表.然后它应该连接成 [Node]
并用作覆盖给定 Element
.
的当前 elementNode
的值
我正在努力编写适当的镜头咒语来做到这一点。到目前为止,这是我设法想出的:
over nodes $ concatMapOf someLensMagic (myFun :: Element -> [Node])
它进行了类型检查,但我未能实施 someLensMagic
。对此的帮助将不胜感激。
如果 myFun
解释了您想用 NodeElement
构造函数做什么,并且您想要其他 Node
构造函数的空列表,则可以使用 concatMapOf _Element
。
要为其他构造函数提供单例列表,您应该修改 myFun
以处理 Node
的所有构造函数。那么你可以使用concatMap myFun
,而不是concatMapOf
。 (在这种情况下你可以使用 concatMapOf traverse myFun
,但它更难理解。)
无法编写将生成单例列表的 someLensMagic
,因为无法从 NodeComment
中提取 Element
(例如)。
在 Fold
中以不同方式处理某些子节点的一种方法是使用 to
to put them in different branches of an Either
according to the condition, and then use beside
,该函数可让您将不同的 Traversal
应用于 [=13] 的每个分支=].
比如这个函数应该return一个Element
的子节点Node
,特别是对于满足条件的节点,其子节点是return改为:
foldDifferently :: (Node -> Bool) -> Fold Element Node
foldDifferently p =
nodes
. folded
. to (\n -> if p n then Right n else Left n)
. beside id (_Element . nodes . folded)
我已经结束了两个连续的 concatMap
s:
over nodes (concatMap $ concatMapOf _Element myFun) element
这是一个次优的解决方案,所以我不会将其标记为答案并欢迎任何其他建议。
最直接的解决方案是,,围绕 myFun
编写一个包装器,以便它可以处理 Node
s 而不是 Element
s:
myFun' :: Node -> [Node]
myFun' n = case n of
NodeElement el -> myFun el
_ -> [n]
myFun'
然后可以与普通 concatMap
(与 concatMapOf
相对)一起使用来修改 nodes
字段:
over nodes (concatMap myFun')
碰巧,有一个 lens 魔法可以用作编写包装器的替代方法。 outside
组合器将棱镜变成针对函数的透镜,实际上允许我们编辑函数在特定情况下的作用。实际上,它看起来像这样:
over nodes (concatMap $ set (outside _Element) myFun (:[]))
concatMap
的参数是一个函数,其行为类似于 (:[])
,除非参数匹配 _Element
,在这种情况下,它在基础元素上变为 myFun
。也就是说,本质上是抽象的模式匹配。为了说明问题,我们可以尝试使用 outside
:
来模仿上面 myFun'
的定义风格
myFun' :: Node -> [Node]
myFun'
= outside _Element .~ myFun
$ \n -> [n]
我正在使用 xml-lens 包来处理 XML。
给定一个 Element
,我想对其 elementNode :: [Node]
字段执行类似 concatMap
的计算。具体来说,满足某些条件的 NodeElement
应该产生更多的 NodeElement
s,而所有其他情况(NodeElement
s 的其余部分和其他 Node
构造函数)应该产生一个单例列表.然后它应该连接成 [Node]
并用作覆盖给定 Element
.
elementNode
的值
我正在努力编写适当的镜头咒语来做到这一点。到目前为止,这是我设法想出的:
over nodes $ concatMapOf someLensMagic (myFun :: Element -> [Node])
它进行了类型检查,但我未能实施 someLensMagic
。对此的帮助将不胜感激。
如果 myFun
解释了您想用 NodeElement
构造函数做什么,并且您想要其他 Node
构造函数的空列表,则可以使用 concatMapOf _Element
。
要为其他构造函数提供单例列表,您应该修改 myFun
以处理 Node
的所有构造函数。那么你可以使用concatMap myFun
,而不是concatMapOf
。 (在这种情况下你可以使用 concatMapOf traverse myFun
,但它更难理解。)
无法编写将生成单例列表的 someLensMagic
,因为无法从 NodeComment
中提取 Element
(例如)。
在 Fold
中以不同方式处理某些子节点的一种方法是使用 to
to put them in different branches of an Either
according to the condition, and then use beside
,该函数可让您将不同的 Traversal
应用于 [=13] 的每个分支=].
比如这个函数应该return一个Element
的子节点Node
,特别是对于满足条件的节点,其子节点是return改为:
foldDifferently :: (Node -> Bool) -> Fold Element Node
foldDifferently p =
nodes
. folded
. to (\n -> if p n then Right n else Left n)
. beside id (_Element . nodes . folded)
我已经结束了两个连续的 concatMap
s:
over nodes (concatMap $ concatMapOf _Element myFun) element
这是一个次优的解决方案,所以我不会将其标记为答案并欢迎任何其他建议。
最直接的解决方案是,myFun
编写一个包装器,以便它可以处理 Node
s 而不是 Element
s:
myFun' :: Node -> [Node]
myFun' n = case n of
NodeElement el -> myFun el
_ -> [n]
myFun'
然后可以与普通 concatMap
(与 concatMapOf
相对)一起使用来修改 nodes
字段:
over nodes (concatMap myFun')
碰巧,有一个 lens 魔法可以用作编写包装器的替代方法。 outside
组合器将棱镜变成针对函数的透镜,实际上允许我们编辑函数在特定情况下的作用。实际上,它看起来像这样:
over nodes (concatMap $ set (outside _Element) myFun (:[]))
concatMap
的参数是一个函数,其行为类似于 (:[])
,除非参数匹配 _Element
,在这种情况下,它在基础元素上变为 myFun
。也就是说,本质上是抽象的模式匹配。为了说明问题,我们可以尝试使用 outside
:
myFun'
的定义风格
myFun' :: Node -> [Node]
myFun'
= outside _Element .~ myFun
$ \n -> [n]