GHC因UndecidableSuperClasses而卡住-预期行为或错误?

时间:2018-11-29 20:14:10

标签: haskell typeclass type-families constraint-kinds undecidable-instances

以下代码片段使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

我认为它卡住了,因为GHC试图找到t,这导致C T通过类型族F T C扩展回{{1} },这就是它要查找的内容(无限循环)。

我认为从理论上讲,GHC可以说它达到了自己对F的追求,而依赖于它的任何事物都可以递归地工作,还是我误会了某些东西?

旁注:在我偶然发现此行为的真实示例中,我可以通过用Data.Constraint.Dict代替C T来实现所需的功能,而不会卡住编译器。

1 个答案:

答案 0 :(得分:5)

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开头附近的内容,他描述了“达到固定点”的过程。

考虑一个有效的示例(从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