haskellhxt

HXT: Adding elements to a tree based on a list


I'm struggling using arrows in the HXT library to generate elements in a tree based on a list (the line with mapM below).

mkqelem (mkQName vns "depositInstruction" pacNS) []  
    [selem "key" 
        [selem "accountId" [txt $ pacuAccountId pacUpdate],
         selem "instructionId" [txt $ pacuInstructionId pacUpdate]
        ],
     selem "totalAmount" [txt $ pacuTotalAmount pacUpdate],
     mapM mkInvestment  [(120, 10.0)]
     ]

mkInvestment :: ArrowXml a => (Fund, Amount) -> a n XmlTree
mkInvestment x = selem "investments" [selem "investmentId" [txt $ show $ fst x],selem "amount" [txt $ show $ snd x]] 

The program won't compile, I get the following:

• Couldn't match type ‘[]’ with ‘XN.NTree’
  Expected type: a n XmlTree
    Actual type: a n [XmlTree]
• In the expression: mapM mkInvestment [(120, 10.0)]
  In the third argument of ‘mkqelem’, namely
    ‘[mkelem
        "key" [] [selem "accountId" [...], selem "instructionId" [...]],
      selem "totalAmount" [txt $ pacuTotalAmount pacUpdate],
      mapM mkInvestment [(120, 10.0)]]’
  In the expression:
    mkqelem
      (mkQName vns "depositInstruction" pacNS)
      []
      [mkelem
         "key" [] [selem "accountId" [...], selem "instructionId" [...]],
       selem "totalAmount" [txt $ pacuTotalAmount pacUpdate],
       mapM mkInvestment [(120, 10.0)]]

I've tried replacing mapM with variations of +=, but I don't have a good intuition on mapping in Arrows. Any pointers?


Solution

  • Your issue doesn't actually involve arrows; rather, it has to do with mapM being unnecessary here. A plain fmap over the list of tuples to make the element arrows, following by appending the result to the list with the rest of your elements, should be enough.

    mkqelem (mkQName vns "depositInstruction" pacNS) [] $
        [selem "key" 
            [selem "accountId" [txt $ pacuAccountId pacUpdate],
             selem "instructionId" [txt $ pacuInstructionId pacUpdate]
            ],
         selem "totalAmount" [txt $ pacuTotalAmount pacUpdate]
         ]
        ++ fmap mkInvestment [(120, 10.0), (121, 15.0)]
    

    As for (+=), it adds children to a node, so you wouldn't use it instead of mapM/fmap, but rather, for instance, to define mkInvestment in a different manner:

    mkInvestment :: ArrowXml a => (Fund, Amount) -> a n XmlTree
    mkInvestment x = eelem "investments"
        += (eelem "investmentId" += (txt $ show $ fst x))
        += (eelem "amount" += (txt $ show $ snd x))
        -- Minor style suggestion: you might prefer to use pattern matching here 
        -- instead of fst and snd.