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更深入一些.)
谢谢!
如果将箭头转换为(然后从)确定性版本,则这将按预期工作:
> 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
(更好的错误消息等)。