Actually, @Chris Taylor's answer is incorrect. You can see this with the following commands (in GHCi):
>view (at 0 . unsafeFromJust) (fromList [(0,'b')])
*** Exception: Maybe.fromJust: Nothing
[expected: *** Exception: setJust]
>set (at 1 . unsafeFromJust) 'c' (fromList [(0,'b')])
*** Exception: setJust]
[expected: fromList [(0,'b'),(1,'c')]
The first command still throws an error when looking up a value that doesn't exist, but it doesn't throw the right error. For the second test, I am unable to insert new keys, which doesn't seem to make sense.
Instead, I'm using the following two combinators:
at' :: (Ord a) => a -> Lens' (Map a b) b
at' a = lens r s
where r m = case lookup a m of
(Just b) -> b
Nothing -> error "Could not find key in map!"
s m b' = insert a b' m
at'' :: (Ord a) => a -> Lens (Map a b) (Map a b) b (Maybe b)
at'' a = lens r s
where r m = case lookup a m of
(Just b) -> b
Nothing -> error "Could not find key in map!"
s m Nothing = delete a m
s m (Just b') = insert a b' m
at'
is how (at k . unsafeFromJust)
should work: attempting to retrieve a non-existent value throws an error, inserting a new value succeeds. at''
is similar: it allows you to read pure values, but you set Maybe
values. This allows you to delete keys in the map.
Examples:
> view (at' 0) (fromList [(0,'b')])
'b'
> view (at'' 0) (fromList [(0,'b')])
'b'
> view (at' 1) (fromList [(0,'b')])
*** Exception: Could not find key in map!
> view (at'' 1) (fromList [(0,'b')])
*** Exception: Could not find key in map!
> set (at' 0) 'c' (fromList [(0,'b')])
fromList [(0,'c')]
> set (at'' 0) (Just 'c') (fromList [(0,'b')])
fromList [(0,'c')]
> set (at' 1) 'c' (fromList [(0,'b')])
fromList [(0,'b'),(1,'c')]
> set (at'' 1) (Just 'c') (fromList [(0,'b')])
fromList [(0,'b'),(1,'c')]
> set (at'' 0) Nothing (fromList [(0,'b')])
fromList []