HXT:左保理不确定性箭头?

Ale*_*rov 7 haskell arrows hxt

我正在尝试与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]
Run Code Online (Sandbox Code Playgroud)

所以Parse是一个小帮助函数,它将我给它的任何箭头应用于普通的XML文档

<root>
  <a>foo</a>
  <b>bar</b>
  <c>baz</c>
</root>
Run Code Online (Sandbox Code Playgroud)

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

> 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")]
Run Code Online (Sandbox Code Playgroud)

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

> parse (extract "a" &&& extract "b" >>^ arr (\(a,b) -> (b,a))) 
[("bar","foo")]
Run Code Online (Sandbox Code Playgroud)

现在来了我不明白的部分:我想留下因素!两次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"))
[]
Run Code Online (Sandbox Code Playgroud)

请注意,我已尝试将调用重新命令为isElem等,以便查明是否存在问题.但就目前而言,我只是不知道为什么这不起作用.在Haskell维基上有一个箭头'教程' 和我理解它的方式,它应该可以做我想做的事情 - 即用于&&&配对两个计算的结果.

它确实有效 - 但只是在箭头链的开头,而不是中途低谷,当我已经有一些结果时,我想保持'共享'.我觉得我只是无法解决正常功能构成和箭头符号之间的想法差异.我非常感谢任何指针!(即使它只是一些通用的箭头教程,比Haskell-wiki更深入一些.)

谢谢!

Tra*_*own 2

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

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

不过,这并不是很令人满意,而且我一时记不起为什么(&&&)使用非确定性箭头会这样做(我个人会使用这种proc/do表示法来表示比这更复杂的东西)。


更新:runLA和似乎发生了一些奇怪的事情xread。如果您使用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")]
Run Code Online (Sandbox Code Playgroud)

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