Объединение призм при извлечении полей JSON с помощью Lens-Aeson

У меня есть большой двоичный объект JSON, похожий на следующий:

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

Обратите внимание, что некоторые версии являются числами, а некоторые — строками. Я хочу получить список версий. Я могу использовать следующую комбинацию линз для извлечения числовых версий:

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

И следующее для извлечения строк

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

Но как я могу получить список версий за один проход по списку? Есть ли какой-нибудь комбинатор линз, который берет линзы AL._Number . to show и AL._String . to T.unpack и возвращает комбинированный геттер, чтобы в случае неудачи первого пробовать второй? Что-то вроде msum для объективов?


person Hapal    schedule 14.10.2016    source источник


Ответы (2)


На самом деле существует комбинатор, который пробует оптику и переходит к резервному, если первый выходит из строя. Это называется сбой .

Обратите внимание, что условие на нем должно удовлетворяться описанным вами случаем. Даже если бы это было не так, комбинатор все равно работал бы, просто при рефакторинге он вел бы себя неправильно. (Что является основной проблемой при использовании отфильтровано как Traversal.)

person Carl    schedule 15.10.2016
comment
Хороший. Я подозревал, что ответ будет в Control.Lens.Traversal, но мой взгляд прошел мимо этого комбинатора среди всех остальных :) - person duplode; 15.10.2016
comment
@duplode Я полностью понимаю. Там есть много. - person Carl; 15.10.2016

Перед ответом Карла, который вы должны использовать, я собирался предложить outside как способ выполнить анализ ситуации с помощью этих призм:

tryNumberThenString :: AL.AsPrimitive t => t -> [String]
tryNumberThenString =
    outside AL._Number .~ (:[]) . show $
    outside AL._String .~ (:[]) . T.unpack $
    const []
v1 = obj ^.. AL.values . AL.key fieldName . folding tryNumberThenString

Обратите внимание, что, если я не упустил какой-то другой трюк, это не только сложнее, чем то, что предлагает Карл, но и менее гибко - я могу получить Fold только из простой функции tryNumberThenString, в то время как failing объединяет призмы в Traversal.

person duplode    schedule 15.10.2016