7

我正在尝试与 Haskell 的 XML 工具箱 ( HXT ) 达成协议,但我在某处碰壁,因为我似乎没有完全掌握箭头作为一种计算工具。

这是我的问题,我希望使用 GHCi 会话更好地说明:

> let parse p = runLA (xread >>> p) "<root><a>foo</a><b>bar</b><c>baz</c></root>"
> :t parse
parse :: LA XmlTree b -> [b]

所以 Parse 是一个小的辅助函数,它将我给它的任何箭头应用到琐碎的 XML 文档

<root>
  <a>foo</a>
  <b>bar</b>
  <c>baz</c>
</root>

我定义了另一个辅助函数,这次是提取具有给定名称的节点下面的文本:

> let extract s = getChildren >>> isElem >>> hasName s >>> getChildren >>> getText 
> :t extract
extract :: (ArrowXml cat) =>
   String -> cat (Data.Tree.NTree.TypeDefs.NTree XNode) String
> parse (extract "a" &&& extract "b") -- extract two nodes' content.
[("foo","bar")]

在这个函数的帮助下,很容易使用&&&组合器来配对两个不同节点的文本,然后,比如说,将它传递给构造函数,如下所示:

> parse (extract "a" &&& extract "b" >>^ arr (\(a,b) -> (b,a))) 
[("bar","foo")]

现在到了我不明白的部分:我想左因子!extract两次调用getChildren根节点。相反,我希望它只调用一次!所以我首先得到根节点的孩子

> let extract' s = hasName s >>> getChildren >>> getText
> :t extract'
extract' :: (ArrowXml cat) => String -> cat XmlTree String
> parse (getChildren >>> isElem >>> (extract' "a" &&& extract' "b"))
[]

请注意,我已尝试重新排序对 isElem 等的调用,以确定是否是问题所在。但就目前而言,我只是不知道为什么这不起作用。Haskell wiki上有一个箭头“教程” ,按照我的理解,它应该可以做我想做的事情——即使&&&用来配对两个计算的结果。

它也确实有效——但只是在箭头链的开始,而不是在低谷的中间,当我已经有了一些结果时,我想保持“共享”。我有一种感觉,就是无法理解正常函数组合和箭头符号之间的想法差异。我会非常感谢任何指针!(即使它只是一些比 Haskell-wiki 更深入的通用箭头教程。)

谢谢!

4

1 回答 1

2

如果您将箭头转换为(然后从)确定性版本,这将按预期工作:

> let extract' s = unlistA >>> hasName s >>> getChildren >>> getText
> parse (listA (getChildren >>> isElem) >>> (extract' "a" &&& extract' "b"))
[("foo","bar")]

但是,这并不令人满意,而且我不记得为什么(&&&)使用不确定的箭头会以这种方式表现(我个人会将该proc/do符号用于比这更复杂的任何事情)。


更新:这里似乎发生了一些奇怪的事情runLAxread。如果您使用runX并且readString一切都按预期工作:

> let xml = "<root><a>foo</a><b>bar</b><c>baz</c></root>"
> let parse p = runX (readString [] xml >>> p)
> let extract' s = getChildren >>> hasName s >>> getChildren >>> getText
> parse (getChildren >>> isElem >>> (extract' "a" &&& extract' "b"))
[("foo","bar")]

这意味着您必须在IOmonad 中运行解析器,但runX无论如何使用都有好处(更好的错误消息等)。

于 2010-11-18T23:32:11.153 回答