2017-03-19 87 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