2017-03-19 28 views
1

假设有一个数据类型JSON嵌套序列

​​

它有一个对应的JSON视图

例如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,) 

回答

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变量,函数,并得到了那些令人毛骨悚然的错误)。并且您需要为您的V数据类型派生Generic才能使其工作。而且你需要在内部使用pair函数,而不是在一个地方使用.=。下面是完整版本:

{-# 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)]) 
+0

不错,那'toEncoding'? –

+0

@ДМИТРИЙМАЛИКОВ我已经更新了答案。 – Shersh