使用GHC.Exts.Constraint
类型,我有一个广义的存在量化数据结构,如下所示:
data Some :: (* -> Constraint) -> * where
Specimen :: c a => a -> Some c
(实际上,我的类型比这更复杂;这只是一个简化的例子)
现在,假设我有一个函数,例如,需要Enum
约束,我想对Some c
采取行动。我需要做的是检查Enum
是否隐含c
约束:
succSome :: Enum ⊆ c => Some c -> Some c
succSome (Specimen a) = Specimen $ succ a
在这种情况下,我如何实施⊆
运算符?有可能吗?
答案 0 :(得分:5)
首先请注意Enum
和c
本身不是约束:它们有* -> Constraint
种,而不是Constraint
种。因此,您要使用Enum ⊆ c
表达的内容是:c a
隐含所有Enum a
的{{1}}。
使用a
中的:-
,我们可以在值级别编码约束Data.Constraint
的见证:
d ⊆ c
我们希望在type Impl c d = forall a . c a :- d a
的定义中使用Impl
,如下所示:
succSome
但是这会因类型错误而失败,并说GHC无法从succSome :: Impl c Enum -> Some c -> Some c
succSome impl (Specimen a) = (Specimen $ succ a) \\ impl
中推断c a0
。看起来GHC选择了非常通用的类型c a
,然后无法推断出impl :: forall a0 . c a0 :- d a0
。对于从c a0
中提取的类型变量impl :: c a :- d a
,我们更喜欢更简单的a
类型。看起来我们必须帮助输入一点推理。
为了向Specimen
提供明确的类型注释,我们必须引入impl
和a
类型变量(使用c
扩展名)。
ScopedTypeVariables
这样可行,但问题并不完全是问题。
问题要求使用类型类对succSome :: forall c . Impl c Enum -> Some c -> Some c
succSome impl (Specimen (a :: a)) = (Specimen $ succ a) \\ (impl :: c a :- Enum a)
约束进行编码。我们可以通过使用单个方法来实现这一目标:
d ⊆ c
要实际使用此功能,我们必须为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)
提供实例。例如:
Impl