我有以下功能:
parseUserBasic :: ByteString -> Either String [Either String UserBasic]
parseUserBasic x = do
xx <- parseItems x
pure $ fmap (eitherDecode . encode) (items xx)
但是它不是很有效,因为 pure $ fmap (eitherDecode . encode) (items xx)
- 我们将 Object
JSON 编码为 ByteString
,然后我们将其解码为 UserBasic
。有没有办法直接做到这一点?我假设此函数的类型为 FromJSON a => Value -> Maybe a
。
完整代码:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
module UserBasic where
import GHC.Generics
import Data.Aeson
import Data.String.Conversions
import Data.ByteString.Lazy
data UserBasic = UserBasic
{ email :: String
, name :: String
, address_1 :: Maybe String
, address_2 :: Maybe String
, address_3 :: Maybe String
, address_4 :: Maybe String
} deriving (Generic, Show)
data Items = Items
{ items :: [Object]
} deriving (Generic, Show)
instance FromJSON Items where
instance ToJSON Items where
toEncoding = genericToEncoding defaultOptions
instance FromJSON UserBasic where
parseJSON = withObject "Person" $ \v -> UserBasic
<$> v .: "email"
<*> ((++) . (++ " ") <$> v .: "first_name" <*> v .: "last_name")
<*> v .: "first_name"
<*> v .: "first_name"
<*> v .: "first_name"
<*> v .: "first_name"
parseItems :: ByteString -> Either String Items
parseItems = eitherDecode
parseUserBasic :: ByteString -> Either String [Either String UserBasic]
parseUserBasic x = do
xx <- parseItems x
pure $ fmap (eitherDecode . encode) (items xx)
最佳答案
我推荐以下缩写代码:
newtype Items = Items
{ items :: [UserBasic]
} deriving (Generic, Show)
instance FromJSON Items
instance ToJSON Items where
toEncoding = genericToEncoding defaultOptions
parseUserBasic :: ByteString -> Either String [UserBasic]
parseUserBasic bs = items <$> eitherDecode bs
-- OR, even better in many cases, don't bother unwrapping Items:
parseItems :: ByteString -> Either String Items
parseItems = eitherDecode -- why even bother naming parseItems lmao
不要先解码为Object
,再解码;只需直接解码为您关心的类型即可。
关于Haskell Aeson 如何基于 `Value` 类型而不是 `ByteString` 进行解码/解析?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63073992/