2

我正在尝试使用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起初听起来很有希望,但该函数仅停止对特定子树的处理,因此它仍将转换除嵌套元素之外的所有元素。

4

1 回答 1

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箭头。如果这不是您想要的,您可以尝试收集所有孩子(使用 eg listA)并纯粹处理它们。

因此,该解决方案并不理想,但我希望它可以帮助您作为起点。

于 2012-04-21T18:44:12.070 回答