2016-12-17 2 views
2

Der Versuch, die JSON-de-Serialisierung für einen Datentyp mit TypeLits zu tun, erhalte ich mit dem folgenden Problem stecken:FromJSON Instanz mit DataKinds

 
Couldn't match type ‘n’ with ‘2’ 
     ‘n’ is a rigid type variable bound by 
     the instance declaration at test.hs:14:10 
     Expected type: aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser 
         (X n) 
     Actual type: aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser 
         (X 2) 

Wie wäre es, die korrekte Syntax Nat allgemein in ermöglichen, die FromJSON Instanz in folgendem Beispiel:

{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE GADTs #-} 
{-# LANGUAGE OverloadedStrings #-} 

import GHC.TypeLits 
import Data.Aeson 
import Control.Monad (mzero) 

data X (n :: Nat) where 
    A :: Integer -> X 1 
    B :: Integer -> X 2 

instance FromJSON (X n) where 
    parseJSON (Object o) = do 
     v <- o .: "val" 
     t <- o .: "type" 
     case t of 
     "a" -> return $ A v 
     "b" -> return $ B v 
    parseJSON _  = mzero 
+1

Sie benötigen wahrscheinlich separate Instanzen für 'FromJSON (X 1)' und 'FromJSON (X 2)', oder tun Sie einen Schreibweisen auf 'n' (mit einem Singleton). Die Art, wie Sie die Instanz geschrieben haben, besagt, dass Sie "X n" für jedes "n" lesen können, das der * Aufrufer * wählt. – luqui

Antwort

1

Da Sie offensichtlich nicht den Typen kennen, können Sie bei der Kompilierung deserialisiert werden, muss die genaue Art in versteckt werden ein existentielles und dann über Mustervergleich wiederhergestellt. Normalerweise verwende ich einen generischen Typ Some, um Phantomtypen zu verbergen.

{-# LANGUAGE PolyKinds #-} 

data Some (t :: k -> *) where 
    Some :: t x -> Some t 

Jetzt können Sie die Instanz als

instance FromJSON (Some X) where 
    parseJSON (Object o) = do 
     v <- o .: "val" 
     t <- o .: "type" 
     case (t :: String) of 
      "a" -> return $ Some $ A v 
      "b" -> return $ Some $ B v 
    parseJSON _  = mzero 

jedoch schreiben, müssen Sie auch die FlexibleInstances Erweiterung ermöglichen.

+0

Sie können 'FlexibleInstances' vermeiden, indem Sie ein spezielles 'data SomeX = forall n' verwenden. SomeX (X n) ', wenn Sie möchten. Was gewinnt die generische Version? – dfeuer

+0

Nichts in diesem einfachen Beispiel, sicher. Ich wollte jedoch die allgemeinere Version einschließen, da Sie normalerweise mehrere verschiedene Typen in einer Anwendung haben, aus der Sie den Typparameter vorübergehend ausblenden möchten. – shang

Verwandte Themen