質問

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")]

この機能を利用すると、簡単に使用できます。 &&& コンビネーターを使用して 2 つの異なるノードのテキストをペアにし、それを次のようにコンストラクターに渡します。

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

ここで私が理解できない部分が来ます:左因数分解したい! extract 電話をかける getChildren ルートノード上で 2 回実行します。代わりに、一度だけ呼び出すようにしたいのです。したがって、最初にルートノードの子を取得します

> 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 で そして私がそれを理解した方法では、 すべき 私がやりたいことをその方法で実行できるようにする — つまり、 &&& 2 つの計算の結果をペアにするためです。

それも機能します - しかし、私がすでにいくつかの結果を持っているとき、私が「共有」したいという結果があるとき、矢印鎖の開始時にのみ、途中のトラフではありません。私は、通常の関数の構成と矢印表記の間のアイデアの違いに頭を包むことができないだけだと感じています。ご指摘をいただければ幸いです。(たとえそれが、Haskell-wiki よりももう少し詳しく書かれた一般的な矢印チュートリアルだとしても。)

ありがとう!

役に立ちましたか?

解決

矢印を決定論的バージョンに変換すると (そして決定論的バージョンから変換すると)、これは期待どおりに機能します。

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

しかし、これはあまり満足のいくものではなく、その理由が頭から思い出せません。 (&&&) 非決定的な矢印でこのように動作します(私は個人的には 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")]

これは、パーサーを実行する必要があることを意味します。 IO モナドですが、使用する利点があります runX とにかく(エラーメッセージの改善など)。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top