我是 Haskell 的新手,来自命令式编程背景。我希望能够以“Haskell 方式”将对象序列化为 JSON,但还不太确定如何做到这一点。
我读过了RealWorldHaskell 第 5 章 http://book.realworldhaskell.org/read/writing-a-library-working-with-json-data.html其中讨论了一点 JSON,并使用了 Aeson。我还查看了一些用 Haskell 编写的 JSON API 库,例如:
- Haskell 中的 Facebook API https://github.com/prowdsponsor/fb
- Haskell 中的 Stripe API https://github.com/michaelschade/hs-stripe
这让我能够从对象创建非常基本的 JSON 字符串(也感谢这篇博文 http://no-fucking-idea.com/blog/2014/03/23/shortest-way-to-work-with-json-in-haskell/):
{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}
import Data.Aeson
import GHC.Generics
data User = User {
email :: String,
name :: String
} deriving (Show, Generic)
instance ToJSON User
main = do
let user = User "[email protected] /cdn-cgi/l/email-protection" "Hello World"
let json = encode user
putStrLn $ show json
这将打印出:
"{\"email\":\"[email protected] /cdn-cgi/l/email-protection",\"name\":\"Hello World\"}"
现在的目标是,向User
可以具有任意字段的实例。 Facebook Graph API 有一个名为data
,这是一个 JSON 对象,具有您想要的任何属性。例如,您可以向 Facebook 的 API 发出这样的请求(伪代码,不太熟悉 Facebook API):
POST api.facebook.com/actions
{
"name": "read",
"object": "book",
"data": {
"favoriteChapter": 10,
"hardcover": true
}
}
前两个字段,name
, and object
是类型String
,而data
字段是任意属性的映射。
问题是,实现这一目标的“Haskell 方式”是什么?User
上面的型号?
我可以理解如何做这个简单的案例:
data User = User {
email :: String,
name :: String,
data :: CustomData
} deriving (Show, Generic)
data CustomData = CustomData {
favoriteColor :: String
}
但这并不完全是我想要的。这意味着User
类型,当序列化为 JSON 时,将始终如下所示:
{
"email": "",
"name": "",
"data": {
"favoriteColor": ""
}
}
问题是,你如何做到这一点,所以你只需要定义它User
输入一次,然后可以附加任意字段data
属性,同时仍然受益于静态类型(或任何接近静态类型的东西,但还不太熟悉类型的细节)。