2016-03-24 3 views
1

は、このデータを考える:引数なしのコンストラクタが複数ある代数データ型のToJSON/FromJSONエントリの作成方法は?

data A1 = A1 | A2 | A3 

は、どのように私はそれのためのインスタンスを作成することができますか?

instance ToJSON A1 where 
    toJSON = ??? 

instance FromJSON A1 where 
    parseJSON = ??? 

それは、単一のコンストラクタだった場合、私はそれを行うことができると思いますが、私は、任意のパラメータを受け入れない複数のものでそれを行う方法を見つけ出すことはできません。

UPDATE: 各コンストラクタについて、私はこれらのエラーを持っている:toJSONparseJSON関数は、引数それぞれを取る

my-app/src/Lib.hs:54:32: 
    No instance for (ToJSON a1) arising from a use of ‘.=’ 
    The type variable ‘a1’ is ambiguous 
    Note: there are several potential instances: 
     instance ToJSON UUID -- Defined in ‘Data.UUID.Aeson’ 
     instance ToJSON MyType -- Defined at src/Lib.hs:53:10 
     instance ToJSON MyType2 -- Defined at src/Lib.hs:70:10 
    In the expression: "tag" .= "A1" 
    In the first argument of ‘object’, namely ‘["tag" .= "A1"]’ 
    In the expression: object ["tag" .= "A1"] 

my-app/src/Lib.hs:54:35: 
    No instance for (Data.String.IsString a1) 
     arising from the literal ‘"A1"’ 
    The type variable ‘a1’ is ambiguous 
    Note: there are several potential instances: 
     instance Data.String.IsString Value 
     -- Defined in ‘aeson-0.9.0.1:Data.Aeson.Types.Internal’ 
     instance (a 
       ~ bytestring-0.10.6.0:Data.ByteString.Internal.ByteString) => 
       Data.String.IsString 
       (attoparsec-0.13.0.1:Data.Attoparsec.ByteString.Internal.Parser a) 
     -- Defined in ‘attoparsec-0.13.0.1:Data.Attoparsec.ByteString.Char8’ 
     instance Data.String.IsString 
       bytestring-0.10.6.0:Data.ByteString.Builder.Internal.Builder 
     -- Defined in ‘bytestring-0.10.6.0:Data.ByteString.Builder’ 
     ...plus 13 others 
    In the second argument of ‘(.=)’, namely ‘"A1"’ 
    In the expression: "tag" .= "A1" 
    In the first argument of ‘object’, namely ‘["tag" .= "A1"]’ 
+5

JSONへの変換は、あなた次第ですが、通常私は、コンストラクタを示すタグのいくつかの並べ替えを期待しています。 'toJSON A1 - >" {'tag': 'A1'} ''などとなります。 'インスタンスToJSON A1 'の –

答えて

2

編集で示された問題は、関数アプリケーションを使用して型を推測できないようにするか型の注釈を追加することで解決できる型のあいまいさに関するものです。

  • .=の右側には、文字列リテラルであるのでStringまたはTextや他の人かもしれない - 私は下記やるとText.pack . showを使用するよう::Textとその注釈を付けたりください。
  • .:の結果は多相であり、ケースパターンはすべて同じ問題を引き起こす文字列リテラルです。以下では、:: Texttagを追加して、あいまいさを取り除いています。

完全なコード:

{-# LANGUAGE OverloadedStrings #-} 

import Data.Aeson 
import Data.Aeson.Types 
import Control.Monad 
import Data.Text as Text 

data A1 = A1 | A2 | A3 
    deriving (Eq, Ord, Show) 


instance ToJSON A1 where 
    toJSON a = object ["tag" .= Text.pack (show a)] 

instance FromJSON A1 where 
    parseJSON (Object o) = do 
     tag <- o .: "tag" 
     case (tag :: Text) of 
      "A1" -> return A1 
      "A2" -> return A2 
      "A3" -> return A3 
      _ -> mzero 
    parseJSON v = typeMismatch "A1" v 
+0

なぜあなたはjsonで「タグ」と呼んだのですか? –

+0

それは共通用語です。あなたは、データ構造に「タグ付け」して、可能な値の和集合(合計型)が実際に表現されているかどうかを示します。私は基本的にあなたの質問の下で私の最初のコメントでこれを言った。 –

2

toJSONための最も簡単で、おそらくです:

instance ToJSON A1 where 
    toJSON A1 = object ["tag" .= "A1"] 
    toJSON A2 = object ["tag" .= "A2"] 
    toJSON A3 = object ["tag" .= "A3"] 

それから、あなただけのその逆を行う必要がありますparseJSON

instance FromJSON A1 where 
    parseJSON (Object o) = do 
     tag <- o .: "tag" 
     case tag of 
      "A1" -> return A1 
      "A2" -> return A2 
      "A3" -> return A3 
      _ -> mzero 

これはキー "tag"の値を抽出し、返されるTextでパターンマッチングを実行して、使用するコンストラクタを決定します。

+0

ここで、A1はクラスの名前ですが、次の3つはコンストラクタです。つまり、第2のA1はコンストラクタです。 –

+1

@AlanCoromano最初の 'A1'は_data型の名前です.'class'はHaskellで異なる意味を持っています。次の3つはコンストラクタです。 'データA = A1 | A2 |インスタンスA2、インスタンスToJSON A ...、インスタンスAsJSON A、...、 – bheklilr

+0

そして私は何を言ったのですか? –

関連する問題