Is there a Lens/Optic that can use to dig deeply into multidimensional maps?
Asked Answered
F

0

8

I've had a bit of difficulty using Lenses with Maps. I have maps that look like this Map String (Map String Int). These are multidimensional arrays, and I usually set them up with known dimensions. I often want to read and update elements of these Maps, but not add or delete elements.

I want an optic, similar to ix "k1" . ix "k2" that allowed me to do the following:

myfunc :: Map String (Map String Int) -> ()
myfunc m =
  let m' = m & ix "k1" . ix "k2" %~ (+1)
      v = m ^. ix "k1" . ix "k2"
  in () 

Unfortunately, I can't use ix "k1" . ix "k2" because the v = m ^. ix "k1" . ix "k2" won't compile because Int isn't a Monoid. In general, I can't have this Monoid restriction because I generally hold fairly complex values in my maps (like some complex state ADT). (I'm guessing this Monoid restriction is there so that ix can return a default value if the key doesn't exist.) I want an optic without this Monoid restriction and that would just throw a fatal error if I try indexing with a key that doesn't exist. Is it possible to create such a thing on my own?

Fuentes answered 26/6, 2020 at 19:14 Comment(4)
Do you mean (^?) or (^?!)?Bridges
hackage.haskell.org/package/lens-4.19.2/docs/…Needlepoint
@Bridges awesome, replacing ^. ^?! works for my purposes! I didn't realize I had this degree of freedom.Fuentes
You need Monoid to combine results of a traversal. (^?!) takes only the first result, so there's no need to combine, so no Monoid constraint. (^?) wraps it in a Maybe, as there may in fact be no results at all.Bridges

© 2022 - 2024 — McMap. All rights reserved.