Is it possible to set default values if Nothing is encountered somewhere in a deep Lens lookup/assignment?

E.g. for lookup:

(Just (4, 3), 2) ^. _1 . (maybe (6, 5)) . _1 == 4
(Nothing,     2) ^. _1 . (maybe (6, 5)) . _1 == 6

Or perhaps more importantly, for assignment:

((Just (4, 3), 2) & _1 . (maybe (6, 5)) . _1 .~ 7) == (Just (7, 3), 2)
((Nothing,     2) & _1 . (maybe (6, 5)) . _1 .~ 7) == (Just (7, 5), 2)
2

There are 2 answers

2
freestyle On BEST ANSWER

You can use non :: Eq a => a -> Iso' (Maybe a) a to create Iso between Eq a => Maybe a and Eq => a (see also).

(Nothing, 2) ^. _1 . non (6, 5) . _1 == 6
((Nothing, 2) & _1 . non (6, 5) . _1 .~ 7) == (Just (7, 5), 2)
2
Wizek On

Yes, it seems to be possible:

let
  df :: Functor f => a -> (a -> f b) -> Maybe a -> f (Maybe b)
  df d = lens (maybe d id) (const Just)

(Just (4, 3), 2) ^. _1 . df (6, 5) . _1 `shouldBe` 4
(Nothing,     2) ^. _1 . df (6, 5) . _1 `shouldBe` 6

((Nothing,     2) & _1 . df (6, 5) . _1 .~ 7) `shouldBe` (Just (7, 5), 2)
((Just (4, 3), 2) & _1 . df (6, 5) . _1 .~ 7) `shouldBe` (Just (7, 3), 2)

Note: I'm in the process of acquainting myself with Lenses, so if anyone knows of a better way of doing this please do tell — e.g. in case there is a built-in function equivalent to df.