Получение коллекции значений из JSON ByteString с использованием Lens-Aeson

Скажем, у меня есть JSON ByteString, который выглядит примерно так

{
    messages: [
        {...},
        {...}
    ]
}

Я хотел бы использовать объектив, чтобы получить из него список/вектор сообщений. У меня есть функция toMessage, которая может превратить Value в Maybe Message.

Я пробовал эту композицию key "messages" . values . to toMessage (to из Control.Lens.Getter, но результат Maybe Message и просто становится Nothing.

В настоящее время я делаю это

msgsJson <- c ^? key "messages"
let msgs = toList $ mapMaybe message $ msgsJson ^.. values

(mapMaybe из witherable, toList для преобразования Vector в список), но я хотел бы знать, есть ли способ скомпоновать различные линзы, чтобы получить одну линзу, которая делает это.


person Luka Horvat    schedule 21.04.2016    source источник


Ответы (1)


Хм, это работает для меня:

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Data.ByteString (ByteString)

import Control.Lens
import Data.Aeson
import Data.Aeson.Lens

newtype Message =
  Message Integer
  deriving (Show)

toMessage :: Value -> Maybe Message
toMessage json_ = do
  i <- json_ ^? key "a" . _Integer
  return (Message i)

input :: ByteString
input = "{\"messages\":[{\"a\":1},{\"a\":2},{\"a\":3}]}"

main :: IO ()
main =
  print (input ^.. (key "messages" . values . to toMessage))
λ> main
[Just (Message 1),Just (Message 2),Just (Message 3)]

Если вы получаете Nothing, это может означать, что ваш JSON недействителен (вы можете проверить его с помощью decode json :: Maybe Value). Или что любая другая оптика в составе выходит из строя. С длинной точечной оптикой иногда трудно точно сказать, какой из них неисправен, кроме как отрезать части с конца и повторить попытку. Но ваша комбинированная оптика key "messages" . values . to toMessage должна просто работать™.

Кстати:

msgJson <- c ^? key "messages"
let msgs = toList $ mapMaybe message $ msgsJson ^.. values

должно быть таким же, как

msgJson <- c ^? key "messages"
let msgs = toList $ msgsJson ^.. (values . to message . _Just)

а также

msgJson <- c ^? key "messages"
let msgs = msgsJson ^.. (values . to message . _Just)

а также

let msgs = c ^.. (key "messages" . values . to message . _Just)
person hao    schedule 22.04.2016
comment
Хм, надо будет еще раз попробовать. Посмотрите, что я сделал не так в первый раз. - person Luka Horvat; 24.04.2016