HXT:如何在第一次成功转型后停止处理?

时间:2012-04-21 17:01:03

标签: haskell hxt

我正在尝试使用Control.Arrow.ArrowTree来构建一个HTML处理箭头,该箭头在给定树中第一次成功转换(深度优先)后停止。即类型为

的函数
processFirst :: (ArrowTree a, Tree t) => a (t b) (t b) -> a (t b) (t b)

例如,要将类“first”添加到HTML文档中的第一个列表项,可以构建箭头

processFirst (hasName "li" `guards` addAttr "class" "first")

我对HXT很陌生,我现在已经阅读了API文档几个小时,并试图弄清楚如何实现processFirst,但我无法适应所有拼凑在一起。 processTopDownUntil一开始听起来很有希望,但该函数只停止对特定子树的处理,因此它仍然会转换除嵌套子元素之外的所有元素。

1 个答案:

答案 0 :(得分:1)

我不确定我是否完全理解这个问题,但我会尽力回答:)

让我们尝试下一个:

test = flip runLA undefined $ xshow $
  constA "<xml><x>X1</x><x>X2</x></xml>" >>> xread
  >>> processFirst (hasName "x" `guards` addAttr "class" "first")

processFirst f = f `orElse` processChildren (processFirst f)

processFirst的定义与processTopDownUntil的定义相同。此函数将输出如下内容:

["<xml><x class=\"first\">X1</x><x class=\"first\">X2</x></xml>"]

问题应该很清楚 - 如果顶级节点f失败,那么将为每个孩子调用processFirst。如果某个孩子f成功,我们需要一种方法来中止其他孩子的处理。

可能的解决方案是使用状态箭头:

processFirst f = fromSLA False process
  where
  process = (getState >>> isA not)
            `guards`
            (f >>> changeState (const $ const True))
            `orElse`
            processChildren process

想法是在f成功时设置状态并在处理之前检查它。

注意:现在f应为SLA箭头。如果它不是您想要的,您可以尝试收集所有孩子(使用例如listA)并纯粹处理它们。

所以,解决方案并不理想,但我希望它能帮助你作为一个起点。