使用 Aeson 解析带有嵌套列表的列表

Parsing list with nested list using Aeson

当尝试使用 Aeson 解析一些简单的 JSON 时,我收到一个我不明白的类型错误。我有以下 JSON

jsonString = "[\"a\", [\"b\", \"c\"]]" :: L.ByteString

并且我定义了以下导入和代码:

import Data.Aeson
import GHC.Generics
import qualified Data.ByteString.Lazy as L

data Ch = Ch {
   c1 :: String,
   c2 :: (String, String)
} deriving (Show, Generic)
instance FromJSON Ch

当我尝试在我的 Ch 类型的字符串上使用 eitherDecode 时,出现错误

*Aeson> eitherDecode jsonString :: Either String Ch
Left "Error in $: expected record (:*:), encountered Array"

谁能解释一下这个错误并告诉我应该如何解析这个 JSON?

一种可行的方法是

eitherDecode jsonString :: Either String (String, (String, String))

但我宁愿直接转到我的类型。

如果您已经知道按预期解析的类型,那么最简单的解决方案可能就是根据该类型编写您的实例并进行翻译:

import Data.Aeson
import GHC.Generics
import qualified Data.ByteString.Lazy as L

data Ch = Ch {
   c1 :: String,
   c2 :: (String, String)
} deriving (Show, Generic)

instance FromJSON Ch where
    parseJSON x =
        do (a,(b,c)) <- parseJSON x
           pure (Ch a (b,c))

结果是:

*Main> :set -XOverloadedStrings
*Main> eitherDecode "[\"a\", [\"b\", \"c\"]]" :: Either String Ch
Right (Ch {c1 = "a", c2 = ("b","c")})

编辑:

更直接的使用 Aeson 的 API 可以提供信息或首选:

instance FromJSON Ch where
    parseJSON =
       withArray "Ch" $ \arr ->
       -- from Data.Aeson.Types
           if V.length arr /= 2
              -- ^ from Data.Vector
              then typeMismatch "Length should be 2" (Array arr)
                   -- ^ from Data.Aeson.Types
              else Ch <$> parseJSON (arr ! 0) <*> parseJSON ( arr ! 1 )