Aeson - 只需解码 ByteString -> 值

Luk*_*vka 3 haskell

有时 Haskell 真的很令人沮丧 :) 我正在寻找任何函数来简单地将 ByteString 转换为一个值。一切似乎都只是在谈论将 ByteString 直接转换为最终类型。

我这样做的原因是将 JSON 转换为 Value,然后“预提取”包含“真实数据”的 Value 部分,并且只传递“真实数据”(许多类型之一)以进行特定类型的解码,因此这部分不会在每个 parseJSON 实例中重复。

编辑:感谢大家的回答,我忘了展示真正的问题,也许有更好的解决方案:

所以,我正在构建 API 客户端,API 返回包装在“数据”对象中的所有内容。

获取数据集

{
  "data": {
    "id": "WkzbQMuFYuamGv3YF",
    "name": "d7b9MDYsbtX5L7XAj",
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

我把它解析成

data Dataset = Dataset {
  name :: String,
  id :: String,
  ...
}
Run Code Online (Sandbox Code Playgroud)

然后是更复杂的响应类型,分页 GET List Datasets

{
  "data": {
    "total": 2,
    "offset": 0,
    "limit": 1000,
    "desc": false,
    "count": 2,
    "items": [
      {
        "id": "WkzbQMuFYuamGv3YF",
        "name": "d7b9MDYsbtX5L7XAj",
        ...
      },
      ...
     ]
  }
}
Run Code Online (Sandbox Code Playgroud)

我使用更通用的类型,因为还有其他东西的分页

data PaginationList a = PaginationList {
    total :: Int,
    offset :: Int,
    limit :: Int,
    desc :: Bool,
    count :: Int,
    items :: [a]
} deriving Show
Run Code Online (Sandbox Code Playgroud)

现在,这很好地组合并且里面的数据集会自动解析,除了我必须在每次解析时删除的“数据”包装器。因此,这种幼稚的尝试不起作用,因为在 items :: [a] (其中 a 成为数据集)中,我会尝试从“数据”中解开每个数据集。

因此,我想到的解决方案是将 JSON 预先解析为 Value 以摆脱“数据”,然后所有类型都会很好地组合。

Wil*_*sem 5

Value 是 的一个实例FromJSON,因此您可以使用decode :: FromJSON a => ByteString -> Maybe a

Prelude Data.Aeson> decode "{\"menu\": {\"id\": \"file\", \"value\": \"File\", \"popup\": {\"menuitem\": [1,4,2,5]}}}" :: Maybe Value
Just (Object (fromList [("menu",Object (fromList [("popup",Object (fromList [("menuitem",Array [Number 1.0,Number 4.0,Number 2.0,Number 5.0])])),("value",String "File"),("id",String "file")]))]))
Run Code Online (Sandbox Code Playgroud)

所以实际上根本没有什么可定义的,您也可以使用decode解码为 a Value。但是,您可能应该指定签名以使其清楚,decode "4" :: Maybe Value例如。

decode 的返回类型是 a Maybe Value,因为并不是说ByteString您提供的是有效的JSON 流。如果您绝对确定它是有效的 JSON,则可以使用fromJust :: Maybe a -> a. 但是实现某种回退机制可能会更好。