2014-10-31 4 views
4

오늘 나는 다음 문제를 해결하고 싶었다.Aeson : 기본값을 가진 제네릭

우리가

class DataWithDefault a where 
    defaultValue :: a 

로 정의 DataWithDefault typeclass 있다고 가정 그리고 우리는 내가 아이손 자동 FromJSONToJSON 인스턴스를 도출하기 위해 제네릭을 사용하는 것을 알고

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를 가지고,하지만 난 할 수 주어진 json으로 표현되지 않는 필드에 대해 FromJSON 인스턴스를 기본값으로 파생시키는 방법을 찾아 낼 수 없습니다. 제네릭을 사용하는 것이 가능합니까? 사실 나는 당신에게 최종 해결책을 묻지 않지만 어쩌면 어떤 단서를 물을 것입니까?

업데이트 나 문제에 대한 자세한 정보를 추가 할 수 있습니다.

지금 당신은 당신의 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

+0

오, 내 업데이트를 참조하십시오 – d12frosted

+0

당신이 자신의 typeclass를 만들고 있다면 많은 구조체에 대한 인스턴스를 얻기 위해 대신'Data.Default'를 사용하는 것을 고려해 볼 수 있습니다. – alternative

답변

3

대신 그들은을 위해 설계되었습니다 무엇 아이손 그것은 단지에 대한 newtype은 사용합니까 만드는 : 그럼 당신이 당신이 묻는 것보다 약간 다릅니다

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

을 할 수

newtype DefaultJSON a = DefaultJSON { unDefaultJSON :: a } 

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

, 구문 분석이 실패 할 경우 기본값을 제공하지만 개별 필드가없는 경우 각 필드의 기본값은 제공하지 않습니다.

+0

그래, 할 수는있어.하지만 가능하면 좋을거야. 누락 된 각 필드에 대해 기본값을 설정하십시오. – d12frosted

+0

아, 그리고 내가 Aeson에서 기대하지 않는, 난 그냥 내 문제에 대한 해결책 (합리적인 하나)가 있는지 알아 내려고 : D – d12frosted

+0

@ d12frosted 내가 [이] (http://stackoverflow.com/a/26260503) 쓴/839246)는 다른 날에 하나의 필드에 대한 좋은 해결책이지만, 레코드의 모든 필드에 대해서는 합리적이라고 생각하지 않습니다. 어쩌면 아이디어를 줄 수 있을까요? – bheklilr