I have a deeply nested record which I am trying to rebuild from the database. For example, A
contains many B
records. B
records have many C
records. C
has many D
s. I have functions to query the children of each type of object (f0
, f1
, and f2
below).
f0 :: A -> [B]
f1 :: B -> [C]
f2 :: C -> [D]
I am looking for an elegant way to implement f3
.
f3 :: A -> (A, [(B, [(C, [D])])])
I've read a little bit on Arrows and it feels like they might be a good fit. However, I keep hitting a road block when I try to combine them.
I've started with something like this:
f4 :: A -> (A, [B])
f4 = id &&& f0
which gets me to the first level. However, I'm at a loss to find a way to chain that to another arrow which would map [B]
, return [(B, [C])]
and use that as the second element of the original tuple.
I'm a bit new to Haskell, so please let me know if I need to include any additional information.
Thanks!
Update
Modifying sclv's answer slightly, I now have
data A = A
data B = B
data C = C
data D = D
f0 :: A -> [B]
f0 = undefined
f1 :: B -> [C]
f1 = undefined
f2 :: C -> [D]
f2 = undefined
pairFun f = id &&& f
foo :: A -> (A, [(B, [C])])
foo = fmap (map (pairFun f1)) . pairFun f0
I still can't wrap my mind around how to combine the last function (f2
).
Final update
Thanks to sclv, it turns out this can be done like this:
foo = (fmap . map) ((fmap . map) (pairFun f2) . pairFun f1) . pairFun f0
something like this should work (untested):
pairFun f = id &&& f
foo = (fmap . map) ((fmap . map) (pairFun f2) . pairFun f1) . pairFun f0
edit: one way to think about this, by the way, is using conal's model of semantic editor combinators -- http://conal.net/blog/posts/semantic-editor-combinators