2017-03-19 3 views
1

Supposons qu'il est un type de donnéesJSON sérialisation imbriqué

data V = V { a :: Int, x :: Int, y :: Int } 

Il a un correspondant JSON vue

Par ex V { a = 1, x = 2, y = 3 } doivent être sérialisé comme

{ 
    "a": 1, 
    "nested": { 
    "x": 2, 
    "y": 3 
    } 
} 

Qu'est-ce que ToJSON exemple ressemblerait dans ce cas?


Ce que j'ai essayé:

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

Répondre

1

Voici comment par exemple peut ressembler à:

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 ] 
     ] 

Vous pouvez tester dans 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 (concernant toEncoding):

Vous ne souhaitez probablement pas définir toEncoding. Cette méthode a une implémentation par défaut et est définie à l'aide de la méthode toJSON. Mais la méthode toJSON n'a pas d'implémentation pour le cas général. Il a seulement default implémentation pour Generic types de données.

Votre mise en œuvre si presque bien, sauf qu'il a faute de frappe: "x" .= x <> "y" .= y dans le corps de la méthode et (V a b c) en correspondance de motif (il utilise donc variable en fonction x et vous a ces erreurs rampantes). Et vous devez dériver Generic pour votre type de données V pour que cela fonctionne. Et vous devez utiliser la fonction pair à partir d'internes au lieu de .= en un seul endroit. Voici la version complète:

{-# 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))) 

Mais soyez conscient des incohérences possibles:

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

bien, qu'en est-'toEncoding'? –

+0

@ ДМИТРИЙМАЛИКОВ J'ai mis à jour la réponse. – Shersh