Hapal Hapal - 1 month ago 16
JSON Question

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?

Answer

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.)