我在ToJSON
和FromJSON
看到的每个示例都是针对具有单个构造函数的数据类型,如下所示:
data RewindConfig = RConfig JobID Phase
deriving Show
instance FromJSON RewindConfig where
parseJSON (Object o) = RConfig
<$> o .: "JobID"
<*> o .: "Phase"
parseJSON _ = fail "invalid RewindConfig"
我想我会看看Aeson如何为具有多个构造函数的类型创建实例,例如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 ""
parseJSON中的模式匹配让我困惑,我不明白(H.toList -> [(key, value)])
发生了什么。
我想要创建实例的数据类型如下所示:
data Foo = Bar String
| Baz String
| Bin String
我确实想要做一些我知道如何实施的事情
data Foo = (Maybe Bar) (Maybe Baz) (Maybe Bin)
但这似乎并不令人满意。有人可以通过解释Either
实例的内容来帮助我,也许可以给我一些关于Foo
的To / From实例的指导吗?
更新:我认为Aeson为Maybe
实现的实例更加清晰,并告诉我需要了解的内容。不过,我想知道Either
发生了什么。
答案 0 :(得分:4)
模式(Object (H.toList -> [(key, value)]))
称为view pattern。您可以将其读作以下内容:
parseJSon (Object o) = case H.toList o of
[(key, value)]
| key == left -> Left <$> parseJSON value
| key == right -> Right <$> parseJSON value
它实际上略有不同,因为上面的内容总是会在传递Object o
时提交模式Object
,而视图模式只会在“匹配Object o
模式时提交“和”H.toList o
匹配[(key, value)]
模式“条件成立,但对于此示例无关紧要。
答案 1 :(得分:2)
json包中包含您可能想要采用的数据类型的编码。
如果你只是派生Data
,你可以使用它。它不是很快,但很容易使用。
答案 2 :(得分:1)
假设每个数据类型都有一个不同的键,另一种方法可以使用镜头 - 我喜欢它,因为它简洁且可读。例如,如果你有一个包含A,B和C的包装器,它们都有FromJSON实例:
import Data.Aeson
import Data.Maybe
import Data.Aeson.Lens
import Control.Lens
data Wrap = WrapA A | WrapB B | WrapC C
instance FromJSON Wrap where
parseJSON json
| isJust (json ^? key "A's unique key") = WrapA <$> parseJSON json
| isJust (json ^? key "B's unique key") = WrapB <$> parseJSON json
| isJust (json ^? key "C's unique key") = WrapC <$> parseJSON json
| otherwise = fail "Bad message"