You'd like a lens like
Lens' (Maybe (a, b)) (Maybe a)
but that can't quite be a Lens
since putting back Nothing
affects the b
as well. It can be a Getter
getA :: Getter (Maybe (a, b)) (Maybe a)
getA = to (fmap fst)
but then when you compose it you'll just wind up with a Getter
as well, not a full Lens
maybeFst :: Ord k => k -> Getter (Map k (a, b)) (Maybe a)
maybeFst k = at k . getA
Probably better than that is to use a Traversal
instead
maybeFstT :: Ord k => k -> Traversal' (Map k (a, b)) a
maybeFstT k = at k . _Just . _1
This will allow you to both get (using preview
or toListOf
) and set values at the fst
of the values in your map, but you won't be able to modify its existence in the map: if the value does not exist you cannot add it and if it does exist you cannot remove it.
Finally, we can jury-rig a fake Lens
which has the appropriate type, though we have to give it a default value for b
getA :: b -> Lens' (Maybe (a, b)) (Maybe a)
getA b inj Nothing = (\x -> (,b) <$> x) <$> inj Nothing
getA _ inj (Just (a, b)) = (\x -> (,b) <$> x) <$> inj (Just a)
but notice that it has some not-very-Lens
like behavior.
>>> Just (1, 2) & getA 0 .~ Nothing & preview (_Just . _2)
Nothing
>>> Nothing & getA 0 .~ Just 1
Just (1,0)
so often it's better to avoid these pseudolenses to prevent mishaps.