haskell - 如何在具有自定义类型类约束的 GADT 上实现 fromJSON?
问题描述
我有以下 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 实现基于:
这个 SO Question和 This Blog Post - 模式 2
如下:
{-# 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
'''Message''' 的情况很好。我遇到的问题是错误,例如:
* 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")
在数据构造函数中有我自己的类型类约束(例如 Titled)的任何地方,编译器都会说“否”。有没有办法解决这个问题?
解决方案
存在类型是一种反模式,尤其是当您需要进行反序列化时。StartRun 应该包含一个具体的类型。反序列化无论如何都需要一个具体的类型,因此您不妨将 StartRun 专门用于它。
推荐阅读
- firebase - 可以在 Firebase 分析中注册多少个自定义参数?
- amazon-web-services - 为什么附加到 IAM 用户的此策略不起作用
- c# - 从另一个对象/类型调用成员方法,就好像它们属于该对象/类型一样
- python - python中表示的常见时间格式
- c# - 如何将字符串属性传递给 WCF 并返回数据集?
- angular - 为什么我的项目会导致“在此元素上匹配多个组件”。错误?
- raku - 遍历字符串 (UAX #29)
- go - 在循环中执行一个 goroutine 并将值传递给另一个包中的变量
- c# - System.IO.FileNotFoundException 有神秘的正斜杠
- java - %~dp0 在名称中有空格的文件夹下使用时不起作用