使用DataKinds的FromJSON实例 [英] FromJSON instance with DataKinds
问题描述
尝试使用TypeLits对数据类型进行JSON反序列化时,我陷入了以下问题:
Trying to do the JSON de-serialisation for a data type with TypeLits, I get stuck with the following problem:
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)
在下面的示例中,如何在 FromJSON 实例中普遍允许 Nat 的正确语法:
How would be the correct syntax to allow Nat generically in the FromJSON instance in the following example:
{-# 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
推荐答案
由于您显然不知道在编译时要反序列化的类型,因此确切的类型需要隐藏在一个存在的对象中,然后通过模式匹配进行恢复.我通常使用通用的 Some
类型来隐藏幻像类型.
Since you obviously cannot know the type you are going to deserialize at compile time, the exact type needs to be hidden in an existential and then restored via pattern matching. I usually use a generic Some
type to hide phantom types.
{-# 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
扩展名.
However, you also need to enable the FlexibleInstances
extension.
这篇关于使用DataKinds的FromJSON实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!