4

我见过的每个示例ToJSONFromJSON适用于具有单个构造函数的数据类型,如下所示:

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实例的情况来帮助我吗,或者给我一些关于 To/From 实例的指导Foo

更新:我认为 Aeson 实现的实例Maybe更加清晰,并告诉我我需要知道什么来满足我的需求。不过,我想知道发生了什么Either

4

3 回答 3

4

该模式(Object (H.toList -> [(key, value)]))称为视图模式。你可以像这样阅读它:

parseJSon (Object o) = case H.toList o of
    [(key, value)]
        | key == left  -> Left  <$> parseJSON value
        | key == right -> Right <$> parseJSON value

它实际上略有不同,因为上面将始终提交给模式Object oObject而视图模式只会在“匹配Object o模式”和“H.toList o匹配[(key, value)]模式”条件都成立时提交,但对于这个例子,没有'没关系。

于 2012-04-26T18:55:00.157 回答
2

json 包包含您可能想要采用的数据类型的编码。如果你只是派生Data,你可以使用它。它不是很快,但很容易使用。

于 2012-04-26T18:50:45.177 回答
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"
于 2014-08-28T03:57:53.737 回答