3

TypeLits を使用してデータ型の JSON デシリアライズを実行しようとすると、次の問題が発生します。

タイプ 'n' を '2' と一致させることができませんでした
      'n' は、によってバインドされた固定型変数です。
        test.hs:14:10 でのインスタンス宣言
      予想されるタイプ: aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser
                       (Xn)
        実際のタイプ: aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser
                       (×2)

次の例で、 FromJSONインスタンスで一般的にNatを許可する正しい構文はどのようになるでしょうか。

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

1 に答える 1

3

コンパイル時に逆シリアル化しようとしている型を明らかに知ることはできないため、正確な型を存在に隠してから、パターン マッチングを介して復元する必要があります。Some私は通常、ファントム型を隠すためにジェネリック型を使用します。

{-# LANGUAGE PolyKinds #-}

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

これで、インスタンスを次のように書くことができます

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

ただし、FlexibleInstances拡張機能も有効にする必要があります。

于 2016-12-18T10:25:21.653 に答える