2

ArrowPlusこの質問はHXTに関するものですが、一般的な概念に当てはまると思い ます。次のプログラムを検討してください。

module Main (main) where

import Text.XML.HXT.Core
import Control.Monad (void)

main :: IO ()
main = void $ runX $ root [] [foo]
       >>> writeDocument [withIndent yes] "test.xml"

foo :: ArrowXml a => a XmlTree XmlTree
foo = selem "foo" [bar >>> bar >>> bar]

bar :: ArrowXml a => a XmlTree XmlTree
bar = this <+> eelem "bar"

に何が保存されるか分かりますtest.xmlか? 私の期待:

<?xml version="1.0" encoding="UTF-8"?>
<foo>
  <bar/>
  <bar/>
  <bar/>
</foo>

私のロジック: 矢印barはすべての入力をコピーし、1 つの「バー」要素を追加します (thisアイデンティティ矢印のエイリアスです):

 |     |
this  eelem "bar"
 |     |
 \     /
  \   /
   <+>
    |

したがって、結果は3 つの 'bar' 要素である必要があります (ファミリの矢印は入力を無視し (内容を生成するために使用することはできますが)、新しく作成された要素のみを出力するため、1 つの 'bar' 要素のみになることにbar >>> bar >>> bar注意してください)。 .eelem "bar" >>> eelem "bar"mkelem

test.xml以上のことを踏まえて、プログラム実行後の内容を示します。

<?xml version="1.0" encoding="UTF-8"?>
<foo>
  <//>
  <bar/>
  <bar/>
  <bar/>
  <bar/>
  <bar/>
  <bar/>
  <bar/>
</foo>

質問:

  1. とは<//>?

  2. 'bar' 要素が 3 つではなく 7 つあるのはなぜですか? この重複の理由は何ですか?

  3. なぜ私が得ると置き換えるbar >>> bar >>> barnone >>> bar >>> bar >>> bar

   <?xml version="1.0" encoding="UTF-8"?>
   <foo/>

noneゼロの矢印はどこにありますか。ここでは矢印のモノイドを扱いますよね? none(≡ zeroArrow) はその ID である必要があるため、次のようになります。 none <+> eelem "bar"これは「bar」要素を生成し、後続の呼び出しは 2 つの別の要素を追加する必要があります。しかし、何も得られません!

  1. bar一度に 1 つの「バー」要素を追加する適切なバージョンの矢印を作成するにはどうすればよいですか?

4つも質問して申し訳ありませんが、関係は深いと思いますので問題ありません。

4

1 に答える 1

2

>>><+>演算子の動作に混乱があるようです。直感を構築するために、まず 2 つの異なる を定義しましょうbar

bar1 :: ArrowXml a => a XmlTree XmlTree
bar1 = this <+> eelem "bar"

bar2 :: ArrowXml a => a n XmlTree
bar2 = eelem "bar"

最初に気付くのは型シグネチャです。bar1の入力タイプはXmlTreeです。これは、既存のツリーを何らかの方法で変更する一方でbar2、引数を破棄することを意味します。これは、その要素をコピーするthisinの使用によるものです。それでは、これらを読み込んで、どのように連携するかを理解しbar1ましょう。ghci>>><+>

Prelude Text.XML.HXT.Core> runX $ xshow $ bar2
["<bar/>"]
Prelude Text.XML.HXT.Core> runX $ xshow $ bar2 >>> bar2 >>> bar2
["<bar/>"]

ふむ、変だな、 で何度合成しても同じ構造を作り続ける>>>。これは、 forbar2を変換するたびにツリーを破棄しているためです: 型シグネチャがa n XmlTreeではなく であることを思い出してa XmlTree XmlTreeください。それを比較してみましょうbar1

Prelude Text.XML.HXT.Core> runX $ xshow $ bar1
["<//><bar/>"]
Prelude Text.XML.HXT.Core> runX $ xshow $ bar1 >>> bar1
["<//><bar/><bar/><bar/>"]
Prelude Text.XML.HXT.Core> runX $ xshow $ bar1 >>> bar1 >>> bar1
["<//><bar/><bar/><bar/><bar/><bar/><bar/><bar/>"]

うわー、指数関数的に成長しています!なんで?で構成するたびに>>>、前のツリーを取得し、各要素に対して関数 application を適用しますthis <+> eelem "bar"。の最初の呼び出しにbar1は以前のツリーがないためthis、ルート ノードになり、単純に の要素を追加します<bar/>。ただし、 のbar1 >>> bar1場合、最初のノードbar1が作成<//><bar/>され、2 番目のノードが の各ノード<//><bar/>bar1再度構成するため、次のようになります。

bar1 === <//><bar/>
bar1 >>> bar1 === <//><bar/><bar/><bar/>
                  |--------||----------|
                    First      Second

これを続けると、が前に a が付いたbar1 >>> bar1 >>> bar17 つの s をどのように生成するかがわかります。<bar/><//>

OK、これで直感が得られたので、>>>ArrowXmlどのよう<+>に動作するかを確認できます。

Prelude Text.XML.HXT.Core> runX $ xshow $ bar2 <+> bar2 <+> bar2
["<bar/><bar/><bar/>"]
Prelude Text.XML.HXT.Core> runX $ xshow $ bar1 <+> bar1 <+> bar1
["<//><bar/><//><bar/><//><bar/>"]

ああ、それは非常に簡単です...それらは次々に追加されるだけです。bar1 <+> bar1の型は依然として type の値を変換するものであることがわかりa XmlTree XmlTreeます>>>。この出力に頭を悩ませることができるかどうかを確認してください。

Prelude Text.XML.HXT.Core> runX $ xshow $ (bar1 <+> bar1) >>> bar1
["<//><bar/><bar/><bar/><//><bar/><bar/><bar/>"]
Prelude Text.XML.HXT.Core> runX $ xshow $ bar1 >>> (bar1 <+> bar1)
["<//><bar/><//><bar/><bar/><bar/><bar/><bar/>"]

に関する質問に答えるにはnone、型シグネチャを確認してください。

Prelude Text.XML.HXT.Core> :t none
none :: ArrowList a => a b c

私には、 type の値を取り、 typebの値を返すと言っていますc。が何cであるかがわからないため ( への引数として指定しなかったためnone)、空集合になると想定できます。これは、 と の以前の定義で意味が>>>あり<+>ます。

Prelude Text.XML.HXT.Core> runX $ xshow $ none <+> bar1
["<//><bar/>"]
Prelude Text.XML.HXT.Core> runX $ xshow $ none >>> bar1
[""]

最初のケースでは、別のドキュメントが追加された空のドキュメントは、基本的に ID 操作です。2 番目のものでは、noneは要素を生成しないため、 で構成するとbar1、操作する要素がないため、結果は空のドキュメントになります。none実際、Haskell は怠け者なので、決して評価されないことを知っているので、何を使って構成するかについてさらに無頓着になることができます:

Prelude Text.XML.HXT.Core> runX $ xshow $ none >>> undefined
[""]

この知識があれば、おそらくあなたがやろうとしていたことは次のようなものでした:

Prelude Text.XML.HXT.Core> let bar = eelem "bar"
Prelude Text.XML.HXT.Core> runX $ xshow $ selem "foo" [bar <+> bar <+> bar]
["<foo><bar/><bar/><bar/></foo>"]

編集

同様の解決策は、+=演算子を使用することです。

Prelude Text.XML.HXT.Core> let bars = replicate 3 (eelem "bar")
Prelude Text.XML.HXT.Core> runX $ xshow $ foldl (+=) (eelem "foo") bars
["<foo><bar/><bar/><bar/></foo>"]
于 2015-05-06T21:43:28.067 に答える