2013-10-25 87 views
1

我在計算如何定義FromJSON實例中定義兩種其他類型之間選擇的Enum類型時遇到了一些問題。我的直覺是,我對*>和(。:)運算符以及Aeson對象類型的工作方式沒有足夠的理解,但我無法解析編譯器錯誤然而。 (幸運的是,實例的toJSON是很簡單的。)使用Aeson(Haskell)解碼枚舉選擇

給定兩個孩子的數據類型,我可以這樣定義實例:

data ChoiceSelection = 
    ChoiceSelection 
     { csValue :: Type1 -- Type2 here also works fine 
     } deriving (Show,Typeable) 

data Type1 = 
    Type1 
     { t1Value :: Int 
     } deriving (Show,Typeable) 

data Type2 = 
    Type2 
     { t2Value :: Bool 
     } deriving (Show,Typeable) 

instance FromJSON ChoiceSelection where 
    parseJSON (Object x) = ChoiceSelection 
         <$> (x .: "csValue") 
    parseJSON _   = mzero 

instance FromJSON Type1 where 
    parseJSON (Object x) = Type1 
         <$> (x .: "t1Value") 
    parseJSON _   = mzero 

instance FromJSON Type2 where 
    parseJSON (Object x) = Type2 
         <$> (x .: "t2Value") 
    parseJSON _   = mzero 

instance ToJSON ChoiceSelection where 
    toJSON (ChoiceSelection value) = 
     object [ "csValue" .= value 
      ] 

instance ToJSON Type1 where 
    toJSON (Type1 value) = 
     object [ "t1Value" .= value 
      ] 

instance ToJSON Type2 where 
    toJSON (Type2 value) = 
     object [ "t2Value" .= value 
      ] 

這工作得很好,但我一直無法定義一個實例FromJSON爲ExampleChoice爲:

data ExampleChoice = Choice1 Type1 
        | Choice2 Type2 
        deriving (Show,Typeable) 

data ChoiceSelection = 
    ChoiceSelection 
     { csValue :: ExampleChoice 
     } deriving (Show,Typeable) 

instance FromJSON ExampleChoice where 
    parseJSON (Object x) = -- ??? 
    parseJSON _   = mzero 

instance ToJSON ExampleChoice where 
    toJSON (Choice1 [email protected](Type1 _)) = toJSON t 
    toJSON (Choice2 [email protected](Type2 _)) = toJSON t 

我想試試這個定義作爲MSUM,就像這樣:

instance FromJSON ExampleChoice where 
    parseJSON (Object x) = 
     msum [ -- Some attempt at parsing Type1 
      , -- Some attempt at parsing Type2 
      , mzero 
      ] 
    parseJSON _   = mzero 

但是,我還沒有能夠找出解析。

我還沒有嘗試過使用TemplateHaskell和deriveJSON來爲我定義這個,但即使這不會導致問題,我很好奇如何解決這個問題。

編輯:deriveJSON效果很好。儘管如此,我仍然很好奇如何通過手工來創建它。

回答

1

你需要改變你的ToJSON實例,這樣你可以找出使用該數據的構造函數(我沒有測試的代碼,但我希望這給你的想法):

import qualified Data.HashMap.Strict as H 

instance ToJSON ExampleChoice where 
    toJSON (Choice1 [email protected](Type1 _)) = object ["Choice1" .= t] 
    toJSON (Choice2 [email protected](Type2 _)) = object ["Choice2" .= t] 


instance FromJSON ExampleChoice 
    parseJSON (Object (H.toList -> [(key, value)])) 
     | key == "Choice1" = Choice1 <$> parseJSON value 
     | key == "Choice2" = Choice2 <$> parseJSON value 
    parseJSON _  = fail "" 
+0

我最終沒有得到像這樣工作,使用msum方法。我意識到我的問題是誤解了<$>運營商,現在我更瞭解fmap。我無法得到格式在這個評論工作,但在一行看起來像這樣:parseJSON(Object x)= msum [Choice1 <$> parseJSON x,Choice2 <$> parseJSON x] – stormont

+0

此外,我注意到,自動派生使JSON包裝了ExampleChoice元素中的ChoiceN元素,但該解決方案很好地「隱藏」了JSON中顯示的ExampleChoice功能。 – stormont

+0

這不會解析。 –