2013-10-25 5 views
1

다른 두 가지 유형 중 하나를 선택하는 Enum 유형에 대해 FromJSON 인스턴스를 정의하는 방법을 파악하는 데 문제가 있습니다. 필자의 직감은 < *> 및 (. :) 연산자에 대한 충분한 지식과 Aeson Object 유형의 작동 방식을 충분히 이해하지 못했지만 컴파일러 오류를 구문 분석 할 수 없었습니다. 아직. (고맙게도 ToJSON 인스턴스는 간단하다.)Aeson (Haskell)을 사용하여 Enum 선택 디코딩

두 개의 하위 데이터 유형을 감안할 때,이 같은 인스턴스를 정의 할 수 있습니다

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로 : 그래서 같이 msum으로이 정의하려고 생각했습니다

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 

:

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 인스턴스를 변경해야합니다 (I 코드를 테스트하지 않았하지만 난이 당신에게 아이디어를 제공 희망) :

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을 ChoiceN 요소를 ExampleChoice 요소 내에 포함 시키지만,이 솔루션은 ExampleChoice 기능을 JSON에 표시하지 않도록 멋지게 숨 깁니다. – stormont

+0

구문 분석하지 않습니다. –