I'm pretty new to arrows so go easy on me...
I'm trying to count the number of a specific nodes in an XML file. The XML file is layed out so that under the root, we have a list of scenes and under each scene we have a list of layers which each has a node called 'recs'. I want to count the number of rects in each scene. I don't fully understand how HXT works.
I shall copy an extract of my code that is causing the problem
process :: IOSArrow XmlTree [XmlTree]
process getScene >>. map func
where func a = a >>> getLayer >>> getRec
Each of those get functions are of type IOSArrow XmlTree XmlTree
Why doesn't this work? And how do I fix it?
Error Message:
count_dirty.hs:20:16: error:
• Couldn't match type ‘Data.Tree.NTree.TypeDefs.NTree XNode’
with ‘IOSLA (XIOState ()) a0 XmlTree’
Expected type: [XmlTree] -> [IOSLA (XIOState ()) a0 XmlTree]
Actual type: [IOSLA (XIOState ()) a0 XmlTree]
-> [IOSLA (XIOState ()) a0 XmlTree]
• In the second argument of ‘(>>.)’, namely ‘map func’
In the second argument of ‘(>>>)’, namely ‘getScene >>. map func’
In the expression:
readDocument [withValidate no] file >>> getScene >>. map func
|
20 | getScene >>. map func
| ^^^^^^^^
Thanks!
You're declaring func
here to be a helper function which takes some a
, and then computes a >>> getLayer >>> getRec
.
As
getRec :: IOSArrow XmlTree XmlTree
(>>>) :: (Category cat) => cat a b -> cat b c -> cat a c
GHC can deduce that a >>> getRec
means that cat ~ IOSArrow, b ~ XmlTree, c ~ XmlTree
, leaving the variable a
with the undecided type IOSArrow a XmlTree
, and so
func :: a -> IOSArrow XmlTree XmlTree
And
map :: (x -> y) -> [x] -> [y]
map func :: [a] -> [IOSArrow XmlTree XmlTree]
Since
(>>.) :: a b c -> ([c] -> [d]) -> a b d
getScene >>. :: ([XmlTree] -> [d]) -> IOSArrow XmlTree d
And now GHC is very certain that a ~ XmlTree, d ~ IOSArrow XmlTree XmlTree
, giving
getScene >>. map func
:: IOSArrow
XmlTree
(IOSArrow XmlTree XmlTree)
The issue comes from your map func
- >>.
expects a pure function as its second argument. func
, in your case, is a function producing an arrow, which is not pure.
I guess you might want to use applyA, which lets you generate an arrow from an input, and then apply that arrow, which is exactly what you're doing here. In this case, you'd write
process = applyA (getScene >>. map func)
...
Note that you're working with list arrows, so the type signature would just be
process :: IOSArrow XmlTree XmlTree