2017-09-01 7 views
2

an einem Teil des servant Suche example, ich sehe:Durch welchen Mechanismus interagiert Generic mit der ToJSON-Klasse von Aeson?

{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE DeriveGeneriC#-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE GeneralizedNewtypeDeriving #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE OverloadedStrings #-} 
{-# LANGUAGE ScopedTypeVariables #-} 
{-# LANGUAGE TypeOperators #-} 

module Main where 

import Prelude() 
import Prelude.Compat 

import Control.Monad.Except 
import Control.Monad.Reader 
import Data.Aeson.Types 
import Data.Attoparsec.ByteString 
import Data.ByteString (ByteString) 
import Data.List 
import Data.Maybe 
import Data.String.Conversions 
import Data.Time.Calendar 
import GHC.Generics 
import Lucid 
import Network.HTTP.Media ((//), (/:)) 
import Network.Wai 
import Network.Wai.Handler.Warp 
import Servant 
import System.Directory 
import Text.Blaze 
import Text.Blaze.Html.Renderer.Utf8 
import qualified Data.Aeson.Parser 
import qualified Text.Blaze.Html 

type UserAPI1 = "users" :> Get '[JSON] [User] 

data User = User 
    { name :: String 
    , age :: Int 
    , email :: String 
    , registration_date :: Day 
    } deriving (Eq, Show, Generic) 

instance ToJSON User 

Als ich die deriving von Generic entfernt, bekam ich folgende Fehlermeldung:

• No instance for (Generic User) 
    arising from a use of ‘aeson-1.1.2.0:Data.Aeson.Types.ToJSON.$dmtoJSON’ 

So scheint es, dass die Generic typeclass Instanz für User ermöglicht instance ToJSON User zu, ich nehme an, ein JSON Encoder für User erstellen.

Was ist die Maschinerie von instance ToJSON User, d. H. Typ Unterschrift, wenn das das richtige Wort ist?

Ich versuche, aus der stack ghci an seiner Art zu betrachten, dh REPL, aber versagt:

λ: >:t instance 
<interactive>:1:1: error: parse error on input ‘instance’ 
λ: >:i instance 
<interactive>:1:1: error: parse error on input ‘instance’ 
+1

'Instanz ToJSON User' ist nur eine regelmäßige Klasseninstanz. Sie sind wahrscheinlich gewohnt, 'Instanz ToJSON User wo {...}' zu sehen. Wenn sich im Rumpf der Instanz nichts befindet, können Sie das 'where' weglassen (wenn Sie' DerivateAnyClass' aktivieren, können Sie sogar 'ToJSON' in die' derivating'-Klausel von 'User' setzen). Der Grund 'Generic' ermöglicht' 'ToJSON'' ist das' ToJSON' hat eine [Standardimplementierung, die auf 'Generic' angewiesen ist (https://hackage.haskell.org/package/aeson-1.2.1.0/docs/Data -Aeson.html # v: toJSON). – Alec

Antwort

3

die bei the source für ToJSON Werfen wir einen Blick:

class ToJSON a where 
    -- | Convert a Haskell value to a JSON-friendly intermediate type. 
    toJSON  :: a -> Value 

    default toJSON :: (Generic a, GToJSON Zero (Rep a)) => a -> Value 
    toJSON = genericToJSON defaultOptions 

Die ToJSON Klasse hat einen Standard toJSON Implementierung mit zusätzlichen Typ Einschränkungen (einschließlich Generic, wie Sie bemerkt haben). Dies erfordert die Erweiterung DefaultSignatures; an der Spitze des Moduls feststellen, können Sie

{-# LANGUAGE DefaultSignatures #-} 

Die andere Einschränkung, GToJSON Zero (Rep a) erlegt einige weitere Beschränkungen für die Struktur von a, und so nicht jeder Typ mit einer Generic Instanz erfüllen diese Unterschrift sehen.

In Bezug auf Ihre Frage zu GHCi: instance ist ein Haskell-Schlüsselwort. Unter Umständen prüfen Sie stattdessen, ob Sie toJSON überprüfen möchten. Dies zeigt Ihnen die gleichen Informationen, die wir in der Quelle sahen:

λ> :i toJSON 
class ToJSON a where 
    toJSON :: a -> Value 
    default toJSON :: (GHC.Generics.Generic a, 
        GToJSON Zero (GHC.Generics.Rep a)) => 
        a -> Value 
    ... 
     -- Defined in ‘aeson-1.1.2.0:Data.Aeson.Types.ToJSON’