【问题标题】:How do I write a ToJSON/FromJSON instance for a datatype with multiple constructors?如何为具有多个构造函数的数据类型编写 ToJSON/FromJSON 实例?
【发布时间】:2012-04-26 18:41:59
【问题描述】:

我看到的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 -&gt; [(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 发生了什么。

【问题讨论】:

    标签: haskell


    【解决方案1】:

    模式(Object (H.toList -&gt; [(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 时,上面将始终提交模式Object o,而视图模式仅在“匹配Object o 模式”和“@987654327”时才会提交@ 匹配 [(key, value)] 模式”条件成立,但对于这个例子来说,这并不重要。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        假设每种数据类型都有一个不同的键,另一种方法可以使用镜头 - 我喜欢它,因为它简洁且易读。例如,如果您有一个围绕 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"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-09-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多