简体   繁体   English

约束子集高阶约束

[英]Constraint subset higher-order constraint

Using the GHC.Exts.Constraint kind, I have a generalized existentially quantified data structure like this: 使用GHC.Exts.Constraint类型,我有一个广义的存在量化数据结构,如下所示:

data Some :: (* -> Constraint) -> * where
  Specimen :: c a => a -> Some c

(In reality, my type is more complex than this; this is just a reduced example) (实际上,我的类型比这更复杂;这只是一个简化的例子)

Now, let's say that I have a function which, for example, requires the Enum constraint, that I want to act on Some c 's. 现在,假设我有一个函数,例如,需要Enum约束,我想对Some c What I need to do is to check whether the Enum constraint is implied by c : 我需要做的是检查c是否隐含Enum约束:

succSome :: Enum ⊆ c => Some c -> Some c
succSome (Specimen a) = Specimen $ succ a

How would I implement the operator in this case? 在这种情况下,我如何实现运算符? Is it possible? 可能吗?

First note that Enum and c are not constraints by themselves: They have kind * -> Constraint , not kind Constraint . 首先请注意, Enumc本身不是约束:它们具有类型* -> Constraint ,而不是类型Constraint So what you want to express with Enum ⊆ c is: ca implies Enum a for all a . 所以你想用Enum ⊆ c express Enum ⊆ c表达的是: ca意味着Enum a for a

Step 1 (explicit witnesses) 第1步(明确证人)

With :- from Data.Constraint , we can encode a witness of the constraint d ⊆ c at the value level: 随着:-Data.Constraint ,我们可以编码约束的见证d ⊆ c在价值层面:

type Impl c d = forall a . c a :- d a

We would like to use Impl in the definition of succSome as follows: 我们想在succSome的定义中使用Impl ,如下所示:

succSome :: Impl c Enum -> Some c -> Some c
succSome impl (Specimen a) = (Specimen $ succ a) \\ impl

But this fails with a type error, saying that GHC cannot deduce c a0 from ca . 但这种类型错误失败了,说GHC不能从ca推断c a0 Looks like GHC chooses the very general type impl :: forall a0 . c a0 :- d a0 看起来GHC选择了非常通用的类型impl :: forall a0 . c a0 :- d a0 impl :: forall a0 . c a0 :- d a0 and then fails to deduce c a0 . impl :: forall a0 . c a0 :- d a0然后无法推导出c a0 We would prefer the simpler type impl :: ca :- da for the type variable a that was extracted from the Specimen . 对于从Specimen中提取的类型变量a ,我们更喜欢更简单的类型impl :: ca :- da Looks like we have to help type inference along a bit. 看起来我们必须帮助类型推断。

Step 2 (explicit type annotation) 第2步(显式类型注释)

In order to provide an explicit type annotation to impl , we have to introduce the a and c type variables (using the ScopedTypeVariables extension). 为了向impl提供显式类型注释,我们必须引入ac类型变量(使用ScopedTypeVariables扩展)。

succSome :: forall c . Impl c Enum -> Some c -> Some c
succSome impl (Specimen (a :: a)) = (Specimen $ succ a) \\ (impl :: c a :- Enum a)

This works, but it is not exactly what the questions asks for. 这是有效的,但这并不是问题所要求的。

Step 3 (using a type class) 第3步(使用类型类)

The questions asks for encoding the d ⊆ c constraint with a type class. 这些问题要求使用类型类对d ⊆ c约束进行编码。 We can achieve this by having a class with a single method: 我们可以通过使用单个方法创建一个类:

class Impl c d where
  impl :: c a :- d a

succSome :: forall c . Impl c Enum => Some c -> Some c
succSome (Specimen (a :: a)) = (Specimen $ succ a) \\ (impl :: c a :- Enum a)

Step 4 (usage example) 第4步(使用示例)

To actually use this, we have to provide instances for Impl . 要实际使用它,我们必须为Impl提供实例。 For example: 例如:

instance Impl Integral Enum where
  impl = Sub Dict

value :: Integral a => a
value = 5

specimen :: Some Integral
specimen = Specimen value

test :: Some Integral
test = succSome specimen

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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