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

时间:2018-03-28 18:15:53

标签: haskell typeclass

我通过执行从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)

这似乎是提出类型系统的合理要求。我想为ToJSON提供演示一个MyType f个实例,我可以为ToJSON (f a)提供ToJSON a• 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)’ 。在逻辑表示法中,这就像是说我可以证明(P(a)⇒P(f(a)))⇒P(h(f))对于某些属性 P 。这似乎很适合我。

不幸的是,我的语法错误如下:

JSONable

看起来QuantifiedConstraints提案会提供此语法,但尚未实现。

我可以尝试通过实现自己的类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) 约束的所有函数。

据我所知,在这种情况下最好的权衡是简单地放弃并编写显式实例:

Private Sub ComboBox2_Change()
    On Error Resume Next
    Dim myRange As Range
    Set myRange = Worksheets("cash").Range("BF:BH")
    Price.Value = Application.WorksheetFunction.VLookup(ComboBox2.Value, myRange, 2, 0)
End Sub

这是否真的与语言一样强大?所需的实例是否只是形成错误?或者实际上是否可以在Haskell中为现有的类型类声明这样的实例?

1 个答案:

答案 0 :(得分:10)

在QuantifiedConstraints到来之前,有一个标准的解决方案来编码像forall a. ToJSON a => ToJSON (f a)这样的约束,这看起来就像你提到的那样,但我们不必放弃使用ToJSON的函数约束

forall a. ToJSON a => ToJSON (f a)是对f的约束:我们可以将其定义为类型类。幸运的是,aeson already has 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)进行了编码。

aeson 中似乎缺少的一种方法是解决给定ToJSON (f a)ToJSON1 f的{​​{1}}约束的方法,但您也可以使用关注newtype(ToJSON a的高级版本):

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)