有时 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 以摆脱“数据”,然后所有类型都会很好地组合。
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. 但是实现某种回退机制可能会更好。