为何定义C1实例时无需UndecidableInstances扩展?
为什么这个实例无需启用UndecidableInstances扩展?
通常在类似场景下定义实例时需要启用UndecidableInstances扩展,但下面的代码却不需要,这是为什么?
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE QuantifiedConstraints #-} import Data.Kind (Type) class (forall a. c a => c (f a)) => C1 c f -- 为什么无需UndecidableInstances就能定义这个实例? instance (forall a. c a => c (f a)) => C1 c f -- 而非必须手动写这样的实例: -- instance C1 Eq Maybe ---------- 以下是上述代码的使用示例 data AnnBoolExpFld backend leaf = AVAggregationPredicates Int (AggregationPredicates backend leaf) class (C1 Eq (AggregationPredicates b)) => Backend b where type AggregationPredicates b :: Type -> Type instance Backend Int where type AggregationPredicates Int = Maybe deriving instance (Eq a, Backend b) => Eq (AnnBoolExpFld b a) main = print $ AVAggregationPredicates 1 (Just 1) == (AVAggregationPredicates 1 (Just 1) :: AnnBoolExpFld Int Int )
原因解析
GHC的实例终止检查规则中,当实例的上下文完全等同于类定义的超类约束时,会被判定为合法,不需要启用UndecidableInstances。
在这个例子里:
C1类的定义要求超类约束forall a. c a => c (f a)- 对应的实例定义正好把这个超类约束作为实例的前提条件
这种情况下,GHC能明确知道这个实例不会引发无限递归的实例搜索——它只是将类的超类约束“重述”为实例的上下文,相当于为所有满足该约束的c和f自动提供C1 c f实例,而非需要手动为每个具体的c和f(比如Eq和Maybe)编写实例。
对比需要UndecidableInstances的场景:如果实例上下文引用了实例本身(比如instance C1 c f => C1 c f),或者上下文的复杂度超出了GHC默认的终止检查规则,才需要启用该扩展来放宽限制。
内容的提问来源于stack exchange,提问作者jberryman
相关产品推荐
相关产品推荐

