I'm having some trouble figuring out how to define FromJSON instances for an Enum type that defines a choice between two other types. My hunch is that I don't have a full enough understanding of the , <*>, and (.:) operators, as well as how the Aeson Object type works, but I haven't been able to parse apart the compilers errors yet. (Thankfully, the ToJSON instance is simple enough.)
Given two child data types, I can define instances like this:
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
]
This works fine, but I've been unable to define an instance for FromJSON for ExampleChoice
as:
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
I've thought to try defining this as an msum, like so:
instance FromJSON ExampleChoice where
parseJSON (Object x) =
msum [ -- Some attempt at parsing Type1
, -- Some attempt at parsing Type2
, mzero
]
parseJSON _ = mzero
But, I haven't been able to figure out that parsing yet.
I haven't yet tried using TemplateHaskell and deriveJSON to define this for me, but even if that doesn't cause problems, I'm curious about how to solve this problem.
Edit: deriveJSON works great. I'm still curious how to build this by hand, though.