better use of HXT and arrows

321 views Asked by At

I ve been using hxt with no problem, but there was a problem since the beginning. See, imagine the following piece of code

liftKeys = atTag "myKeys" >>>
   proc e -> do
      key1 <- getAttrValue "name"   -< e
      key2 <- getAttrValue "chance" -< e
      returnA -< (key1, key2)

I have used it like that trough many documents to parse, and im before the classic programmig problem, lack of abstraction.

<zone id= "greenhill">
  <key name="a" chance = "10" />
  <key name="v"  chance = "10"/>
</zone>

I have four (and more coming) files to parse like this example. Some have 2 attributes, others have 5 , someothers 1 etc I cant be writing different versions of liftKeys according the amount of attributes my file has. The thing is i dont really understand arrows or what im doing u.u There has to be some fold or something to write more simple code.

Do you know a better use of this?

1

There are 1 answers

1
shang On BEST ANSWER

If you have a differing number of attributes, then it seems like the most natural solution to construct an arrow from a list of attribute names. However, to do that, we are going to need a small helper function to turn a list of arrows into a single arrow that produces a list.

arrowList :: Arrow a => [a b c] -> a b [c]
arrowList []         = arr $ const []
arrowList (a:arrows) = proc b -> do
    c  <- a -< b
    cs <- arrowList arrows -< b
    returnA -< (c:cs)

Probably something like this already exists in some arrow utility library, but I wasn't able to find one with a quick search. Here, given a list of arrows [a b c], we merge them into a single arrow by first feeding b to the first arrow and then recursively merging the rest of the list and feeding b to that merged arrow.

I wrote the above function using the arrow notation to make it easier to explain, but you could implement it simply like this:

arrowList :: Arrow a => [a b c] -> a b [c]
arrowList []         = arr $ const []
arrowList (a:arrows) = a &&& arrowList arrows >>> arr (uncurry (:))

Now we can implement the liftKeys function like this

liftKeys :: ArrowXml a => [String] -> a XmlTree [String]
liftKeys keys = atTag "myKeys" >>> arrowList (map getAttrValue keys)

And your original example above could be expressed as liftKeys ["name", "chance"].