I have this code to transform some data:
newtype XXX = XXX
{ xxx :: [ Text ]
} deriving (Eq, Show)
oldToNew
:: [XXX] -> [(Int, [(Int, Text)])]
-> [[(Int, Int, Text)]]
oldToNew xs old = map go1 xs
where
go1 (XXX eqs) = foldr go2 [] eqs
go2 l acc = foldr (go3 l) acc old
go3 l (i, w) acc = foldr (go4 i l) acc w
go4 idx1 label1 (idx2, label2) acc =
if label1 == label2
then (idx1, idx2, label2):acc
else acc
Note two things:
- it threads an accumulator (initially empty) through all folds
- each fold picks up an argument from the previous fold to pass to the next "go"
How would one use Control.Lens and/or Optics to do the above.
Test case:
oldToNewSpec :: Spec
oldToNewSpec =
it "oldToNew" $
oldToNew [ XXX ["this", "that", "also"]
, XXX ["here", "there"] ]
[ (0, [(4, "this")])
, (0, [(1, "here")])
, (1, [(5, "that")])
, (2, [(2, "also")])
, (2, [(3, "there")]) ]
`shouldBe`
[ [(0,4,"this"),(1,5,"that"),(2,2,"also")]
, [(0,1,"here"),(2,3,"there")] ]
I don't think you need lenses to make this significantly more readable. List comprehensions ought to get you where you need to go without too much trouble.
Using a proper data structure will make things significantly more efficient, and probably more readable.