2016-10-14 4 views
1

J'ai un blob JSON similaire à ce qui suit:La combinaison de prismes lors de l'extraction des champs JSON avec lentille Aeson

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

Notez que certaines versions sont des nombres et certains sont des chaînes. Je veux obtenir une liste des versions. je peux utiliser la combinaison de lentilles suivante pour extraire les versions numériques:

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

Et ce qui suit pour extraire les chaînes

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

Mais, comment puis-je obtenir une liste des versions par un seul passage sur la liste? Y at-il un combinateur de lentilles qui prend les lentilles AL._Number . to show et AL._String . to T.unpack et renvoie un getter combiné de sorte que si le premier échoue, essaie le second? Quelque chose comme msum pour les lentilles?

Répondre

2

Il existe en fait un combinateur qui essaie une optique et passe en sauvegarde si le premier échoue. C'est ce qu'on appelle failing.

Notez que les conditions y relatives doivent être remplies dans le cas qui vous intéresse. Même si ce n'était pas le cas, le combinateur fonctionnerait toujours, il se comporterait de façon irrégulière lors du refactoring. (Quel est le principal problème avec l'utilisation filtered comme Traversal.)

+0

Nice. Je soupçonnais que la réponse serait dans 'Control.Lens.Traversal', mais mes yeux ont passé ce combinateur parmi tous les autres :) – duplode

+0

@duplode Je comprends totalement. Il y a un * lot * là-dedans. – Carl

0

Avant Carl's answer, qui est ce que vous devez utiliser, je voulais vous proposer outside comme un moyen d'effectuer des analyses de cas avec ces prismes:

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 

Notez que, à moins d'une autre astuce que je suis absent, cela est non seulement plus compliqué que ce que Carl suggère, mais aussi moins flexible - je peux seulement obtenir une Fold de la fonction plaine tryNumberThenString, tandis que failing combine les prismes dans un Traversal.