It's very difficult to give good title to this question… I'm stuck with HXT again. I understand what I want to do, but I'm not sure how to make it play nicely with arrows. Here I give simplified description of the problem.
Function foo
takes an Int
and returns an arrow:
foo :: ArrowXml a => Int -> a XmlTree XmlTree
Function bar
extracts value of some attribute:
bar :: ArrowXml a => a XmlTree String
Now, I need to write baz
that takes a map from String
s to Int
s and
returns an arrow:
import qualified Data.Map.Lazy as M
baz :: ArrowXml a => M.Map String Int -> a XmlTree XmlTree
Logic of baz
: extract value of the attribute with bar
and look up it in
the map. If M.lookup
returns Just x
, invoke foo x
, otherwise don't do
anything (input of the arrow goes through unchanged).
AFAIK every such an arrow works as a filter, so in reality ArrowXml a => a
XmlTree String
type means that it takes a XmlTree
and returns (possibly
empty) list of String
s. This makes me reformulate logic of baz
. For
given input XmlTree
there may be many strings, every string should be used
to look up an integer and first found integer should be passed to foo
. If
all of them result in Nothing
, don't do anything.
Here what I've come up with:
baz :: ArrowXml a => M.Map String Int -> a XmlTree XmlTree
baz m = this &&& (bar >>> arr (`M.lookup` m)) >>> arr (uncurry f)
where f xml Nothing = xml
f xml (Just x) = foo x xml
-- compiler says: ^^^ not so fast, boy
Could not deduce (ArrowXml (->)) arising from a use of ‘foo’
from the context (ArrowXml a)
bound by the type signature for
baz :: ArrowXml a => M.Map String Int -> a XmlTree XmlTree
Not only compiler doesn't like it, but it's difficult to reason about too.
I took me some time to understand how to accomplish this, because when your
arrow has type like a (b, XmlTree) XmlTree
, you can really use it, because
of type conflicts with the rest of the API.
Here is another solution that seems to be more idiomatic:
baz :: ArrowXml a => M.Map String Int -> a XmlTree XmlTree
baz m = maybe this foo $< (bar >>> arr (`M.lookup` m))
All the magic happens because of
($<)
function. From the documentation:
compute the parameter for an arrow with extra parameters from the input and apply the arrow for all parameter values to the input
See also this section of HXT Wiki: 8.2 Transform external references into absolute references.