FromJSON instance with DataKinds

£可爱£侵袭症+ 提交于 2019-12-23 17:26:40

问题


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)

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

回答1:


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

Now you can write the instance as

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

However, you also need to enable the FlexibleInstances extension.



来源:https://stackoverflow.com/questions/41201843/fromjson-instance-with-datakinds

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!