繁体   English   中英

编写形式`(forall a .Class a => Class(f a))=> Class(Type f)的实例

[英]Writing an instance of the form `(forall a . Class a => Class (f a)) => Class (Type f)`

我通过执行从MyType MaybeMyType Identity的自然转换在我的一个程序中执行默认解析。 我想为这些类型派生一个ToJSON实例。 我知道MaybeIdentity有实例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 fToJSON 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM