Search code examples
jsonhaskellhaskell-lensaesonlenses

Combining prisms when extracting JSON fields with lens-aeson


I have a JSON blob similar to the following:

[
  {
    "version": 1
  },
  {
    "version": "3"
  },
  ...
]

Note that some of the versions are numbers and some are strings. I want to get a list of versions. I can use the following lens combination to extract the numeric versions:

v1 :: [String]
v1 = obj ^.. AL.values . AL.key fieldName . AL._Number . to show

And the following to extract the strings

v2 :: [String]
v2 = obj ^.. AL.values . AL.key fieldName . AL._String . to T.unpack

But, how can I get a list of versions by a single pass over the list? Is there any lens combinator that takes lenses AL._Number . to show and AL._String . to T.unpack and returns a combined getter so that if the first one failes, tries the second one? Something like msum for lenses?


Solution

  • There is in fact a combinator that tries an optic and goes to a backup if the first one fails. It's called failing.

    Note that the condition on it should be satisfied by the case you describe. Even if it wasn't, the combinator would still function, it would just behave irregularly when refactoring. (Which is the main problem with using filtered as a Traversal.)