假设我有以下结构。
data AddressDto = AddressDto
{ addressDtoId :: UUID
, addressDtoCode :: Text
, addressDtoCity :: Maybe Text
, addressDtoStreet :: Text
, addressDtoPostCode :: Text
} deriving (Eq, Show, Generic)
instance FromJSON AddressDto where
parseJSON = genericParseJSON $ apiOptions "addressDto"
instance ToJSON AddressDto where
toJSON = genericToJSON $ apiOptions "addressDto"
toEncoding = genericToEncoding $ apiOptions "addressDto"
这就像你所期望的那样
现在说我想解析一个格式为JSON的结构。
{ UUID: AddressDto, UUID: AddressDto, UUID: AddressDto }
一个合理的Haskell表达方式似乎是:
data AddressListDto = AddressListDto [(UUID, AddressDto)]
创建一个像这样的辅助函数
keyAndValueToList :: Either ServiceError AddressListDto -> Text -> DiscountDto -> Either ServiceError AddressListDto
keyAndValueToList (Left err) _ _ = Left err
keyAndValueToList (Right (AddressListDto ald)) k v = do
let maybeUUID = fromString $ toS k
case maybeUUID of
Nothing -> Left $ ParseError $ InvalidDiscountId k
Just validUUID -> Right $ AddressListDto $ (validUUID, v) : ald
最后再创建一个FromJSON的实例
instance FromJSON AddressListDto where
parseJSON = withObject "tuple" $ \o -> do
let result = foldlWithKey' keyAndValueToList (Right $ AddressListDto []) o
case result of
Right res -> pure res
Left err -> throwError err
这样就不能编译了
Couldn't match type ‘aeson-1.4.5.0:Data.Aeson.Types.Internal.Value’
with ‘AddressDto’
Expected type: unordered-containers-0.2.10.0:Data.HashMap.Base.HashMap
Text AddressDto
有两个问题:
1) 我如何确保Hashmap中的嵌套值被正确地解析为AddressDto.2) 我如何避免将初始值强行转化为一个要么?我是否可以使用一个函数来代替 foldlWithKey'
那没有让我把初始值包成这样?
有趣的答案。要实现 parseJSON
,您可以使用
parseJSON :: Value -> Parser (HashMap Text AddressDto)
...但更好的是,为什么不直接使用类型别名而不是一个新的数据类型,所以。
type AddressListDto = HashMap UUID AddressDto
这个类型已经有一个合适的 FromJSON
实例,那么你甚至不需要自己写任何代码。