GHC 由于 UndecidableSuperClasses 而卡住 - 预期的行为或错误?
GHC stuck due to UndecidableSuperClasses - expected behaviour or bug?
以下代码片段使 GHC(已使用 8.6.2 和 8.4.4 检查)在编译期间卡住:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
import GHC.Exts (Constraint)
data T = T
type family F t (c :: * -> Constraint) :: Constraint
type instance F T c = c T
class F t C => C t where
t :: C T => t
t = undefined
我认为它卡住了,因为对于 t
GHC 试图找到 C T
,这导致 F T C
通过类型族 F
扩展回 C T
,这就是它要找的东西(无限循环)。
我想从理论上讲 GHC 可以告诉它它已经从自身达到了对 C T
的追求,并且任何依赖于自身的东西都可以递归地正常工作,或者我误解了什么?
旁注:在我偶然发现这种行为的真实示例中,通过将 UndecidableSuperClasses
替换为 Data.Constraint.Dict
,我能够在不卡住编译器的情况下实现我想要的。
UndecidableSuperClasses
不会 使实例解析变慢。编译器仍将尽可能扩展超类约束。我相信实例字典中指向超类字典的字段是 strict,并且 GHC 实际上在编译时将它们固定下来。这与 UndecidableInstances
形成对比,它允许 实例约束 被(稍微)延迟处理。
deriving instance Show (f (Fix f)) => Show (Fix f)
会很好用。当为 Show (Fix Maybe)
) 解析一个实例时,GHC 会发现它需要 Show (Maybe (Fix Maybe))
。然后它看到它需要 Show (Fix Maybe)
(它目前正在解析)并接受它,感谢 UndecidableInstances
.
UndecidableSuperClases
所做的只是禁用保证展开不会循环的检查。查看 Ed Kmett's talk 开头附近的位,他在其中描述了过程 "reaching a fixed point"。
考虑一个工作示例(摘自 Data.Constraint.Forall
):
type family Skolem (p :: k -> Constraint) :: k
class p (Skolem p) => Forall (p :: k -> Constraint)
GHC 仅接受 UndecidableSuperclasses
。为什么?因为它不知道该约束可能意味着什么。据它所知,p (Skolem p)
可能会减少到 Forall p
。这实际上可能发生!
class Forall P => P x
-- This definition loops the type checker
foo :: P x => x
foo = undefined
以下代码片段使 GHC(已使用 8.6.2 和 8.4.4 检查)在编译期间卡住:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
import GHC.Exts (Constraint)
data T = T
type family F t (c :: * -> Constraint) :: Constraint
type instance F T c = c T
class F t C => C t where
t :: C T => t
t = undefined
我认为它卡住了,因为对于 t
GHC 试图找到 C T
,这导致 F T C
通过类型族 F
扩展回 C T
,这就是它要找的东西(无限循环)。
我想从理论上讲 GHC 可以告诉它它已经从自身达到了对 C T
的追求,并且任何依赖于自身的东西都可以递归地正常工作,或者我误解了什么?
旁注:在我偶然发现这种行为的真实示例中,通过将 UndecidableSuperClasses
替换为 Data.Constraint.Dict
,我能够在不卡住编译器的情况下实现我想要的。
UndecidableSuperClasses
不会 使实例解析变慢。编译器仍将尽可能扩展超类约束。我相信实例字典中指向超类字典的字段是 strict,并且 GHC 实际上在编译时将它们固定下来。这与 UndecidableInstances
形成对比,它允许 实例约束 被(稍微)延迟处理。
deriving instance Show (f (Fix f)) => Show (Fix f)
会很好用。当为 Show (Fix Maybe)
) 解析一个实例时,GHC 会发现它需要 Show (Maybe (Fix Maybe))
。然后它看到它需要 Show (Fix Maybe)
(它目前正在解析)并接受它,感谢 UndecidableInstances
.
UndecidableSuperClases
所做的只是禁用保证展开不会循环的检查。查看 Ed Kmett's talk 开头附近的位,他在其中描述了过程 "reaching a fixed point"。
考虑一个工作示例(摘自 Data.Constraint.Forall
):
type family Skolem (p :: k -> Constraint) :: k
class p (Skolem p) => Forall (p :: k -> Constraint)
GHC 仅接受 UndecidableSuperclasses
。为什么?因为它不知道该约束可能意味着什么。据它所知,p (Skolem p)
可能会减少到 Forall p
。这实际上可能发生!
class Forall P => P x
-- This definition loops the type checker
foo :: P x => x
foo = undefined