Разбор вложенных массивов в Aeson

Я изо всех сил пытаюсь разобрать приведенный ниже JSON с помощью библиотеки Aeson.
Меня интересует только получение файла 1, но я не могу с ним справиться.
У кого-нибудь есть предложения?

JSON

{"files":[["file1.wav",["file2.jpg","file3.jpg"]]]}

Мой код

data File = File Text deriving (Show, Generic, ToJSON)

instance FromJSON File where
  parseJSON jsn = do
    arrays <- parseJSON jsn
    let x = arrays !! 0 !! 0
    return $ File x

Сообщение об ошибке

"Error in $.files[0][1]: parsing Text failed, expected String, but encountered Array"

person revilotom    schedule 04.04.2020    source источник


Ответы (1)


Проблема заключается в использовании parseJSON для анализа jsn в однородный список. Но "file1.wav" — это строка, а ["file2.jpg", "file3.jpg"] — не строка.

Простое решение состоит в прямом сопоставлении с образцом для json, который представляет собой Value, которое может содержать гетерогенный Array (несмотря на название, на самом деле это синоним Vector из библиотеки vector).

{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import qualified Data.Vector as V
import Data.Text (Text)

newtype File = File Text deriving Show

instance FromJSON File where
  parseJSON json = do
    Array arr <- pure json
    Just (Array arr0) <- pure (arr V.!? 0)
    Just (String txt) <- pure (arr0 V.!? 0)
    pure (File txt)

main :: IO ()
main = print (decode' "[[\"file1\", [\"file2\", \"file3\"]]]" :: Maybe File)

((!?) является безопасный оператор индексации.)

person Li-yao Xia    schedule 04.04.2020
comment
Спасибо большое за Ваш ответ! При попытке скомпилировать ваш код он жаловался на то, что я удалил их обоих, и тогда он, похоже, работал нормально. - person revilotom; 05.04.2020
comment
О, верно. Я искал полную версию head, но потом отвлекся. Я только что исправил это, используя (!?), но удаление Just, как вы сказали, также работает. - person Li-yao Xia; 05.04.2020
comment
Спасибо, я не знал об операторе безопасного индексирования! - person revilotom; 07.04.2020