How do I write a ToJSON/FromJSON instance for a datatype with multiple constructors?
haskell
Solution
The pattern `(Object (H.toList -> [(key, value)]))` is called a view pattern. You can read it as something like this:
parseJSon (Object o) = case H.toList o of
[(key, value)]
| key == left -> Left <$> parseJSON value
| key == right -> Right <$> parseJSON value
It's actually slightly different, since the above will always commit to the pattern `Object o` when handed an `Object`, whereas the view pattern will only commit when both the "matches the `Object o` pattern" and the "`H.toList o` matches the `[(key, value)]` pattern" conditions hold, but for this example that doesn't matter.
Problem
Every example I've seen for `ToJSON` and `FromJSON` are for data types with single constructors, like so : ``` data RewindConfig = RConfig JobID Phase deriving Show instance FromJSON RewindConfig where parseJSON (Object o) = RConfig <$> o .: "JobID" <*> o .: "Phase" parseJSON _ = fail "invalid RewindConfig" ``` I thought I would look to how Aeson makes the instance for a type with multiple constructors, for example `Either`: ``` instance (FromJSON a, FromJSON b) => FromJSON (Either a b) where parseJSON (Object (H.toList -> [(key, value)])) | key == left = Left <$> parseJSON value | key == right = Right <$> parseJSON value parseJSON _ = fail "" ``` The pattern-matching in parseJSON confuses me, I don't understand what is going on with `(H.toList -> [(key, value)])`. The data type I want to make instances for looks like this: ``` data Foo = Bar String | Baz String | Bin String ``` it did occur to me to do something I knew how to implement ``` data Foo = (Maybe Bar) (Maybe Baz) (Maybe Bin) ``` But that seems unsatisfying. Could someone help me out by explaining what's going on with the `Either` instance, and perhaps giving me some guidance on To/From instances for `Foo`? update: I think the instances Aeson implements for `Maybe` are much clearer and tells me what I need to know for my needs. Still, I'd like to know what's going on with `Either`.