假设有数据类型
data V = V { a :: Int, x :: Int, y :: Int }
它有一个相应的JSON视图
E.g。 V { a = 1, x = 2, y = 3 }
需要像
{
"a": 1,
"nested": {
"x": 2,
"y": 3
}
}
在这种情况下,ToJSON
个实例会是什么样子?
我尝试过的事情:
instance ToJSON V where
toEncoding (V a b c) =
pairs ( "a" .= a
<> ("nested" .= pairs ("x" .= x <> "y" .= y))
)
<interactive>:6:10: error:
• No instance for (GHC.Generics.Generic V)
arising from a use of ‘aeson-1.1.1.0:Data.Aeson.Types.ToJSON.$dmtoJSON’
• In the expression:
aeson-1.1.1.0:Data.Aeson.Types.ToJSON.$dmtoJSON @V
In an equation for ‘toJSON’:
toJSON = aeson-1.1.1.0:Data.Aeson.Types.ToJSON.$dmtoJSON @V
In the instance declaration for ‘ToJSON V’
<interactive>:6:68: error:
• No instance for (ToJSON Encoding) arising from a use of ‘.=’
• In the second argument of ‘(<>)’, namely
‘("nested" .= pairs ("x" .= x <> "y" .= y))’
In the first argument of ‘pairs’, namely
‘("a" .= a <> ("nested" .= pairs ("x" .= x <> "y" .= y)))’
In the expression:
pairs ("a" .= a <> ("nested" .= pairs ("x" .= x <> "y" .= y)))
<interactive>:6:87: error:
• No instance for (ToJSON (V -> Int)) arising from a use of ‘.=’
(maybe you haven't applied a function to enough arguments?)
• In the first argument of ‘(<>)’, namely ‘"x" .= x’
In the first argument of ‘pairs’, namely ‘("x" .= x <> "y" .= y)’
In the second argument of ‘(.=)’, namely
‘pairs ("x" .= x <> "y" .= y)’
(0.01 secs,)
答案 0 :(得分:1)
这里的实例可能如下:
data V = V { a :: Int, x :: Int, y :: Int }
instance ToJSON V where
toJSON (V a x y) = object
[ "a" .= a
, "nested" .= object
[ "x" .= x
, "y" .= y ]
]
您可以在ghci
:
ghci> import qualified Data.ByteString.Lazy.Char8 as B
ghci> B.putStrLn $ encode (V 1 2 3)
{"nested":{"x":2,"y":3},"a":1}
UPD (关于toEncoding
):
您很可能不想定义toEncoding
。此方法具有默认实现,并使用toJSON
方法定义。但是toJSON
方法对于一般情况没有实现。 default
数据类型只有Generic
个实现。
你的实现几乎没有问题,除非它在方法体中有错字:"x" .= x <> "y" .= y
和模式匹配中的(V a b c)
(因此它使用x
变量作为函数,你得到了那些令人毛骨悚然的错误)。您需要为Generic
数据类型派生V
才能使其生效。而且您需要在一个地方使用内部而不是.=
的{{3}}函数。这是完整版:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
import Data.Monoid ((<>))
import GHC.Generics (Generic)
import Data.Aeson (ToJSON (..), pairs, (.=))
import Data.Aeson.Encoding.Internal (pair)
data V = V { a :: Int, x :: Int, y :: Int } deriving (Generic)
instance ToJSON V where
toEncoding (V a x y) =
pairs ("a" .= a <> (pair "nested" $ pairs ("x" .= x <> "y" .= y)))
但请注意可能的不一致性:
ghci> encode (V 1 2 3)
"{\"a\":1,\"nested\":{\"x\":2,\"y\":3}}"
ghci> toEncoding (V 1 2 3)
"{\"a\":1,\"nested\":{\"x\":2,\"y\":3}}"
ghci> toJSON (V 1 2 3)
Object (fromList [("a",Number 1.0),("x",Number 2.0),("y",Number 3.0)])