Aeson:具有默认值的泛型

时间:2014-10-31 21:31:16

标签: haskell aeson

今天我想解决下一个问题。

假设我们将类型DataWithDefault定义为

class DataWithDefault a where
  defaultValue :: a

我们将数据Example定义为

data Example =
  Example { field1 :: Text
          , field2 :: Text
          } deriving (Show)

instance DataWithDefault Example where
  defaultValue = Example "Hello" "World"

instance FromJSON Example where
  parseJSON (Object v) =
    Example <$> v .:? "field1" .!= field1 defaultValue
            <*> v .:? "field2" .!= field2 defaultValue
  parseJSON _ = mzero

instance ToJSON Example where
 toJSON (Example f1 f2)  =
    object [ "field1" .= f1
           , "field2" .= f2
           ]

我知道Aeson使用Generics自动派生FromJSONToJSON个实例,但我无法弄清楚如何使用默认值派生FromJSON实例没有在给定的json中表示。是否可以使用泛型?其实我不会问你最终的解决方案,但也许有些线索?

更新

让我添加有关此问题的更多信息。

现在假设您需要更新Example数据,现在定义为

data Example =
  Example { field1 :: Text
          , field2 :: Text
          , field3 :: Int
          } deriving (Show)

所以你想要更新DataWithDefault实例声明

instance DataWithDefault Example where
  defaultValue = Example "Hello" "World" 12

我想做的不是写

instance FromJSON Example where
  parseJSON (Object v) =
    Example <$> v .:? "field1" .!= field1 defaultValue
            <*> v .:? "field2" .!= field2 defaultValue
            <*> v .:? "field3" .!= field3 defaultValue
  parseJSON _ = mzero

并希望自动导出这样的实例定义。更重要的是,我希望不仅针对Example,而且针对DataWithDefault a

更新2

组合.:?.!=的关键是从给定的json中获取尽可能多的字段,并将每个缺少的字段设置为默认值。所以当我们通过时

{ "field1" : "space", "field2" : "ship" }

我希望我的新示例不是field1 = Hello; field2 = World; field3 = 12,而是field1 = space; field2 = ship; field3 = 12

1 个答案:

答案 0 :(得分:3)

不要让Aeson这样做,只需使用新类型来实现它们的目的:

newtype DefaultJSON a = DefaultJSON { unDefaultJSON :: a }

instance (FromJSON a, DataWithDefault a) => FromJSON (DefaultJSON a) where
    parseJSON v = DefaultJSON <$> (parseJSON v <|> pure defaultValue)

然后你可以做

> decode "{}" :: Maybe (DefaultJSON Example)
Just (DefaultJSON {unDefaultJSON = (Example {field1 = "Hello", field2 = "World"}})

这与您提出的内容略有不同,它在解析失败时提供默认值,但在缺少单个字段的情况下不提供每个字段的默认值。