2

I'm still not fully understanding lenses.

applicationState = (
    'a',
    'b',
    (   M.fromList $ zip [1..3]  [11,22,33],
        M.fromList $ zip [4,5,6] [44,55,66],
        M.fromList $ zip [7,8,9] [M.fromList $ zip [2,3,4] ["77","777","7777"],
        M.fromList $ zip [2,3,4] ["88","888","8888"],
        M.fromList $ zip [2,3,4] ["99","999","9999"]] )
    )

Is there a more lens-idiomatic way of doing this:

λ> view (_3 . _3 . at 9) applicationState >>= view (at 4) >>= return . ('9':)
Just "99999"
bheklilr
  • 53,530
  • 6
  • 107
  • 163
FallingSkies
  • 121
  • 1
  • 10
  • `preview (_3 . _3 . ix 9 . ix 4 . to ('9':)) applicationState` – kosmikus Jul 09 '14 at 09:43
  • Reformatted it's easy to see that you do `M.fromList $ zip xs ys` a lot, maybe you should also consider tacking `where fromLists xs ys = M.fromList $ zip xs ys` just below the definition for `applicationState` and replacing all instances with `fromLists`. It'll save you a bit of space, at the very least. – bheklilr Jul 09 '14 at 13:16

1 Answers1

2

You can use traverse :: Traversal (Maybe a) (Maybe b) a b and then use preview:

preview (_3 . _3 . at 9 . traverse . at 4 . traverse . to ('9':)) applicationState

Because ix i = at i . traverse, this can also be written as:

preview (_3 . _3 . ix 9 . ix 4 . to ('9':)) applicationState

You can also modify that way, but if any of the at's fail, nothing will be changed (you cannot insert new elements in your map using a Traversal).


Another way is to use non :: a -> Lens' (Maybe a) a. This only works if the first map (accessed by the lens _3._3) never contains an empty map as a value and the second map never contains an empty string as a value. So the following value would be invalid for applicationState:

('a', 'b', 
  ( M.fromList $ zip [1..3] [11,22,33]
  , M.fromList $ zip [4,5,6] [44,55,66]
  , M.fromList $ zip [7..9] [M.empty] -- No value of this map may be the empty map
  )
)

With non, your example can be written as:

view (_3 . _3 . at 9 . non M.empty . at 4 . non "" . to ('9':)) applicationState

This also allows inserting new entries via setting (if you set and the keys 4 or 9 don't exist yet, they will be created) and deleting entries (if you set to the value "", the key 4 will be removed, and if the map is empty after removing that key, the key 9 will also be removed).

Community
  • 1
  • 1
bennofs
  • 11,873
  • 1
  • 38
  • 62