我在确定如何为Enum类型定义FromJSON实例时遇到了一些麻烦,Enum类型定义了两种其他类型之间的选择。我的预感是我对the< *>和(。:)运算符没有足够的理解,以及Aeson Object类型的工作方式,但我无法解析编译器错误。 (值得庆幸的是,ToJSON实例非常简单。)
给定两个子数据类型,我可以定义这样的实例:
data ChoiceSelection =
ChoiceSelection
{ csValue :: Type1 -- Type2 here also works fine
} deriving (Show,Typeable)
data Type1 =
Type1
{ t1Value :: Int
} deriving (Show,Typeable)
data Type2 =
Type2
{ t2Value :: Bool
} deriving (Show,Typeable)
instance FromJSON ChoiceSelection where
parseJSON (Object x) = ChoiceSelection
<$> (x .: "csValue")
parseJSON _ = mzero
instance FromJSON Type1 where
parseJSON (Object x) = Type1
<$> (x .: "t1Value")
parseJSON _ = mzero
instance FromJSON Type2 where
parseJSON (Object x) = Type2
<$> (x .: "t2Value")
parseJSON _ = mzero
instance ToJSON ChoiceSelection where
toJSON (ChoiceSelection value) =
object [ "csValue" .= value
]
instance ToJSON Type1 where
toJSON (Type1 value) =
object [ "t1Value" .= value
]
instance ToJSON Type2 where
toJSON (Type2 value) =
object [ "t2Value" .= value
]
这很好用,但我无法为ExampleChoice
定义FromJSON的实例:
data ExampleChoice = Choice1 Type1
| Choice2 Type2
deriving (Show,Typeable)
data ChoiceSelection =
ChoiceSelection
{ csValue :: ExampleChoice
} deriving (Show,Typeable)
instance FromJSON ExampleChoice where
parseJSON (Object x) = -- ???
parseJSON _ = mzero
instance ToJSON ExampleChoice where
toJSON (Choice1 t@(Type1 _)) = toJSON t
toJSON (Choice2 t@(Type2 _)) = toJSON t
我曾尝试将其定义为msum,如下所示:
instance FromJSON ExampleChoice where
parseJSON (Object x) =
msum [ -- Some attempt at parsing Type1
, -- Some attempt at parsing Type2
, mzero
]
parseJSON _ = mzero
但是,我还没有弄清楚解析。
我还没有尝试过使用TemplateHaskell和deriveJSON为我定义这个,但即使这不会导致问题,我也很好奇如何解决这个问题。
编辑:deriveJSON效果很好。不过,我仍然很好奇如何手工制作。
答案 0 :(得分:1)
您需要更改您的ToJSON
实例,以便您可以识别要使用的数据构造函数(我没有测试过代码,但我希望这能为您提供这个想法):
import qualified Data.HashMap.Strict as H
instance ToJSON ExampleChoice where
toJSON (Choice1 t@(Type1 _)) = object ["Choice1" .= t]
toJSON (Choice2 t@(Type2 _)) = object ["Choice2" .= t]
instance FromJSON ExampleChoice
parseJSON (Object (H.toList -> [(key, value)]))
| key == "Choice1" = Choice1 <$> parseJSON value
| key == "Choice2" = Choice2 <$> parseJSON value
parseJSON _ = fail ""