It seems like you have some confusion between how the >>>
and <+>
operators work. To build intuition, let's first define two different bar
s:
bar1 :: ArrowXml a => a XmlTree XmlTree
bar1 = this <+> eelem "bar"
bar2 :: ArrowXml a => a n XmlTree
bar2 = eelem "bar"
The first thing we notice is the type signature. bar1
has an input type of XmlTree
, meaning that it modifies an existing tree in some way, whereas bar2
discards its argument. This is due to the use of this
in bar1
that copies its elements. Now, let's load these up in ghci
to figure out how >>>
and <+>
work together:
Prelude Text.XML.HXT.Core> runX $ xshow $ bar2
["<bar/>"]
Prelude Text.XML.HXT.Core> runX $ xshow $ bar2 >>> bar2 >>> bar2
["<bar/>"]
Hm, that's weird, it keeps creating the same structure no matter how many times we compose it with >>>
. This happens because for bar2
, we're discarding the tree each time we transform it: remember it's type signature is a n XmlTree
instead of a XmlTree XmlTree
. Let's compare that to 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/>"]
Woah, it's growing exponentially! Why? Well, each time you compose with >>>
, you're taking the previous tree, and for each element applying the function application this <+> eelem "bar"
. The first invocation of bar1
has no previous tree, so this
becomes the root node and you simply append an element of <bar/>
to it. However, for bar1 >>> bar1
, the first bar1
will create <//><bar/>
and the second one will compose each node of <//><bar/>
with bar1
again, leading to:
bar1 === <//><bar/>
bar1 >>> bar1 === <//><bar/><bar/><bar/>
|--------||----------|
First Second
Now you keep doing that, and you can see how bar1 >>> bar1 >>> bar1
will produce seven <bar/>
s preceded by a <//>
.
OK, so now that we have intuition for >>>
in terms of ArrowXml
we can see how <+>
behaves:
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/>"]
Oh, that's pretty simple... they just append one after the other. We can see that the type of bar1 <+> bar1
is still one that transforms values of type a XmlTree XmlTree
, so you will get some crazy behavior if you combine it with >>>
. See if you can wrap your mind around this output:
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/>"]
To answer your question about none
, check it's type signature:
Prelude Text.XML.HXT.Core> :t none
none :: ArrowList a => a b c
To me that says it takes a value of type b
and returns a value of type c
. Since we have no idea what c
is (we didn't provide it as an argument to none
), we can assume that it's going to be the empty set. This makes sense with our previous definitions of >>>
and <+>
:
Prelude Text.XML.HXT.Core> runX $ xshow $ none <+> bar1
["<//><bar/>"]
Prelude Text.XML.HXT.Core> runX $ xshow $ none >>> bar1
[""]
In the first case, the empty document appended with another document is basically the identity operation. In the second one, none
produces no elements, so when you compose it with bar1
, there are no elements to operate on, and hence the result is the empty document. In fact, since Haskell is lazy we can be even more cavalier about what we compose with none
since we know that it'll never be evaluated:
Prelude Text.XML.HXT.Core> runX $ xshow $ none >>> undefined
[""]
Given this knowledge, what you were probably trying to do was something like this:
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>"]
EDIT
A similar solution is to use the +=
operator:
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>"]