假设您有一个简单的类型,并希望使用 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 中实现这一点?