単純な型があり、それを Aeson で JSON にシリアライズしたいとします。基本的なセットアップは次のとおりです。
{-# LANGUAGE DeriveGeneric #-}
import Data.Aeson (ToJSON)
import Data.Aeson (encode)
import GHC.Generics
data Spotting = Spotting {
state :: String,
bird :: String
} deriving (Show, Generic)
instance ToJSON Spotting
bird
ここで、 andstate
フィールドに加えて、ユーザーが追加/カスタム メタデータを渡すことができるようにしたいとします。野鳥観察の場合、おそらくこれは気温、鳥の密度、潮の位置などです。事前にはわかりませんが、何でもかまいません。
Haskell の Twitter APIのような例を見ると、次のように構成する必要があるように思われます。
data Spotting meta = Spotting {
state :: String,
bird :: String,
meta :: meta
} deriving (Show, Generic)
instance ToJSON meta => ToJSON (Spotting meta)
これまでの私の理解では、これはパラメータ化された型です。目標は、そのオブジェクトから JSON を作成する簡単な方法を作成することです。したがって、次のような関数を定義します。
spotting bird state meta = encode $ Spotting {
state = state,
bird = bird,
meta = meta
}
しかし、ここからどこへ行くべきかはまだわかりません。その関数を次のように呼び出すと:
record = spotting "Snowy Egret" "California" "low tide"
エラーがスローされます(私はHaskellを初めて使用するので、これらすべてを解釈する方法の基本をまだ学んでいます)
No instance for (Data.String.IsString meta0)
arising from the literal `"low tide"'
The type variable `meta0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Data.String.IsString
aeson-0.7.0.6:Data.Aeson.Types.Internal.Value
-- Defined in `aeson-0.7.0.6:Data.Aeson.Types.Internal'
instance a ~ Data.ByteString.Internal.ByteString =>
Data.String.IsString
(attoparsec-0.12.1.2:Data.Attoparsec.ByteString.Internal.Parser a)
-- Defined in `Data.Attoparsec.ByteString.Char8'
instance Data.String.IsString Data.Text.Internal.Text
-- Defined in `Data.Text'
...plus five others
In the third argument of `spotting', namely `"low tide"'
In the expression:
spotting "Snowy Egret" "California" "low tide"
In an equation for `record':
record = spotting "Snowy Egret" "California" "low tide"
ここで何が起こっていますか / どうやってこれを機能させますか?
最終的な目標は、meta
フィールドに文字列を渡すのではなく、次のような型指定されたオブジェクト (ただし、任意のオブジェクトを指定できます) を渡すことです。
record = spotting "Snowy Egret" "California" MyCustomData {
tide = "low"
}
Haskellでこれをどのように達成しますか?