Haskell 如何在具有自定义类型类约束的GADT上实现fromJSON?

Haskell 如何在具有自定义类型类约束的GADT上实现fromJSON?,haskell,typeclass,aeson,gadt,Haskell,Typeclass,Aeson,Gadt,我的GADT如下: {-# LANGUAGE GADTs #-} data LogProtocol a where Message :: String -> LogProtocol String StartRun :: forall rc. (Show rc, Eq rc, Titled rc, ToJSON rc, FromJSON rc) => rc -> LogProtocol rc ... and many more... toJSON是直接的,

我的GADT如下:

{-# LANGUAGE GADTs #-}

data LogProtocol a where
  Message :: String -> LogProtocol String
  StartRun :: forall rc. (Show rc, Eq rc, Titled rc, ToJSON rc, FromJSON rc) 
   => rc -> LogProtocol rc
  ... and many more...
toJSON是直接的,没有显示。 fromJSON实现基于:

详情如下:

{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}

-- tag type is used in to/ from JSON to reduce the use of magic strings
data LPTag = MessageT |
             StartRunT |
             ... and many more...
             deriving (Show, Eq, Enum)

tagList :: Enum a => [a]
tagList = enumFrom $ toEnum 0

$(deriveJSON defaultOptions ''LPTag) 

-- a wrapper to hide the a type param in the GADT
data Some (t :: k -> *) where
  Some :: t x -> Some t

instance FromJSON (Some LogProtocol) where

parseJSON :: Value -> Parser (Some LogProtocol)
parseJSON v@(Object o) =
  let 
    tag :: Maybe LPTag 
    tag = do 
      t <- (HML.lookup "type" o) 
      parseMaybe parseJSON t 

    failMessage :: [Char]
    failMessage = toS $ "Could not parse LogProtocol no type field or type field value is not a member of specified in: " 
                    <> (show(tagList :: [LPTag])) 
                    <> show v

  in 
    maybe  
      (fail failMessage )
      (
        \case 
          MessageT -> Some <$> (Message <$> o .: "txt")    
          StartRunT -> Some <$> (StartRun <$> o .: "runConfig")
      )
      tag        

parseJSON wrng = typeMismatch "LogProtocol" wrng
{-#语言多样性}
{-#语言重载字符串}
{-#语言LambdaCase}
{-#语言模板haskell}
--在to/from JSON中使用标记类型以减少魔法字符串的使用
数据LPTag=MessageT|
StartRunT|
... 还有更多。。。
派生(显示、等式、枚举)
标记列表::枚举a=>[a]
tagList=enumFrom$toEnum 0
$(deriveJSON defaultOptions''LPTag)
--在GADT中隐藏a类型参数的包装器
一些数据(t::k->*),其中
Some::tx->Some t
实例FromJSON(一些日志协议),其中
parseJSON::Value->Parser(一些日志协议)
parseJSON v@(对象o)=
让
也许是LPTag
tag=do
t部分(信息o.:“txt”)
StartRunT->Some(startruno.:“runConfig”)
)
标签
parseJSON wrng=类型不匹配的“LogProtocol”wrng
“消息”的情况很好。我遇到的问题是错误,例如:

* No instance for (Titled x2) arising from a use of `StartRun'
* In the first argument of `(<$>)', namely `StartRun'
  In the second argument of `(<$>)', namely
    `(StartRun <$> o .: "runConfig")'
  In the expression: Some <$> (StartRun <$> o .: "runConfig")
*没有因使用“StartRun”而产生的(标题为x2)实例
*在“()”的第一个参数中,即“StartRun”
在“()”的第二个参数中,即
`(StartRun o.:“运行配置”)'
在表达式中:Some(StartRun o.:“runConfig”)
任何我有自己类型类约束的地方(如标题) 在数据构造函数中,编译器说“否”。
有办法解决这个问题吗?

存在类型是一种反模式,特别是当您需要进行反序列化时。StartRun应该包含一个具体类型。反序列化无论如何都需要一个具体的类型,因此您最好将StartRun专门化为它