2014-10-31 71 views
4

今天我想解決下一個問題。艾森:默認值的仿製藥

假設我們有類型類定義爲

class DataWithDefault a where 
    defaultValue :: a 

DataWithDefault而我們定義爲

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 
      ] 

數據Example我知道埃宋使用泛型自動導出FromJSONToJSON實例,但我可以不知道如何使它得到FromJSON實例的默認值爲未在給定的JSON中表示的字段。是否有可能使用泛型?其實我不會問你最終的解決方案,但也許有一些線索?

更新

讓我補充有關問題的詳細信息。

,現在你需要更新你的Example數據,現在,所以你要更新DataWithDefault實例聲明

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

我想做的事情定義爲

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

假設是不寫

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

+0

難道你不能'fromMaybe defaultValue $ decode jsonContents'? – bheklilr 2014-10-31 21:52:21

+0

噢,看我的更新 – d12frosted 2014-10-31 22:06:19

+0

如果你正在製作你自己的類型類,你可以考慮使用'Data.Default'來獲得很多結構的實例 – alternative 2014-11-01 13:12:43

回答

3

而不是使埃宋做到這一點,只需使用一個NEWTYPE什麼他們設計的:

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"}}) 

這比你的要求略有不同,它在解析失敗時提供默認值,但在個別字段丟失的情況下不提供每個字段的默認值。

+0

好吧,我可以這樣做,但如果它會爲每個缺少的字段設置默認值。 – d12frosted 2014-10-31 22:08:03

+0

哦,我不期待它從艾森,我只想弄清楚是否存在我的問題的解決方案(合理的):D – d12frosted 2014-10-31 22:09:35

+0

@ d12frosted我寫了[this](http://stackoverflow.com/a/26260503/839246)回答前些日子對於單個領域來說是一個很好的解決方案,但我不認爲它對於記錄中的所有領域顯然都是合理的。也許它可以給你一些想法? – bheklilr 2014-10-31 22:14:58