1

我在弄清楚如何为定义其他两种类型之间选择的 Enum 类型定义 FromJSON 实例时遇到了一些麻烦。我的预感是我对 、<*> 和 (.:) 运算符以及 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
             ]

这工作正常,但我一直无法为 FromJSON 定义一个实例ExampleChoice

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 和 derivedJSON 为我定义这个,但即使这不会导致问题,我很好奇如何解决这个问题。

编辑:deriveJSON 效果很好。不过,我仍然很好奇如何手动构建它。

4

1 回答 1

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 ""
于 2013-10-25T08:28:30.790 回答