[英]Writing an instance of the form `(forall a . Class a => Class (f a)) => Class (Type f)`
我通过执行从MyType Maybe
到MyType Identity
的自然转换在我的一个程序中执行默认解析。 我想为这些类型派生一个ToJSON
实例。 我知道Maybe
和Identity
有实例ToJSON a => ToJSON (Maybe a)
和ToJSON a => ToJSON (Identity a)
。
我想声明以下形式的实例:
instance (forall a . ToJSON a => ToJSON (f a)) => ToJSON (MyType f)
这似乎是提出类型系统的合理要求。 我想为MyType f
演示一个ToJSON
实例, 前提是我总能得到每个ToJSON a
ToJSON (fa)
。 在逻辑表示法中,这就像说我可以证明某些属性P (P(a)⇒P(f(a)))⇒P(h(f)) 。 这似乎很适合我。
不幸的是,我得到以下错误的语法:
• Illegal polymorphic type: forall a. ToJSON a => ToJSON (f a)
A constraint must be a monotype
• In the context: (forall a. ToJSON a => ToJSON (f a))
While checking an instance declaration
In the instance declaration for ‘ToJSON (GpgParams f)’
看起来QuantifiedConstraints提议会提供这种语法,但它尚未实现。
我可以尝试通过实现自己的类JSONable
来解决这个约束。
class JSONable f where
jsonize :: f a -> Value
default jsonize :: (ToJSON a, ToJSON (f a)) => f a -> Value
jsonize = toJSON
不幸的是,这意味着放弃使用标准库中需要ToJSON
约束的所有函数。
据我所知,在这种情况下最好的权衡是简单地放弃并编写显式实例:
instance ToJSON (MyType Maybe)
instance ToJSON (MyType Identity)
它是否真的像语言一样强大? 所需的实例是否只是形成错误? 或者实际上是否可以在Haskell中为现有的类型类声明这样的实例?
在QuantifiedConstraints到达之前,有一个标准的解决方案来编码像forall a. ToJSON a => ToJSON (fa)
这样的约束forall a. ToJSON a => ToJSON (fa)
forall a. ToJSON a => ToJSON (fa)
,这看起来就像你提到的那样,但我们不必放弃使用ToJSON
约束的函数。
forall a. ToJSON a => ToJSON (fa)
forall a. ToJSON a => ToJSON (fa)
是对f
的约束:我们可以将其定义为类型类。 幸运的是, 埃宋已经ToJSON1
。
class ToJSON1 f where -- encoding of `forall a. ToJSON a => ToJSON (f a)`
...
并且使用该类有一个功能
toJSON1 :: (ToJSON1 f, ToJSON a) => f a -> Value
如果任何类型F
具有实例ToJSON1 F
,则预期其ToJSON
实例等效于
instance ToJSON a => ToJSON (F a) where
toJSON = toJSON1
所以ToJSON1 F
确实编码了forall a. ToJSON a => ToJSON1 (F a)
forall a. ToJSON a => ToJSON1 (F a)
。
有一两件事,似乎从埃宋缺少的是解决办法ToJSON (fa)
定约束ToJSON1 f
和ToJSON a
,但你也可以使用下面的NEWTYPE(高kinded版本的编码它Identity
):
newtype Id1 f a = Id1 { unId1 :: f a }
instance (ToJSON1 f, ToJSON a) => ToJSON (Id1 f a) where
toJSON = toJSON1 . unId1
然后要定义ToJSON (MyType f)
,我们可以先应用coerce :: MyType f -> MyType (Id1 f)
。
import Data.Coerce
instance ToJSON1 f => ToJSON (MyType f) where
toJSON = (...) . (coerce :: MyType f -> MyType (Id1 f))
{- in "(...)" we can use functions that require "ToJSON (Id1 f a)", which is informally equivalent to "ToJSON (f a)" -}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.