You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 21:22:05