类型级别的Peano号码和不可判定的实例

时间:2016-05-13 21:25:59

标签: haskell type-level-computation

关注this tutorial,我有以下代码:

{-# LANGUAGE DataKinds, TypeFamilies #-}

data Nat = Z | S Nat

type family   Plus (n :: Nat) (m :: Nat) :: Nat
type instance Plus Z     m = m
type instance Plus (S n) m = S (Plus n m)

到目前为止一切顺利。我知道DataKinds会自动将类型提升为种类,TypeFamilies会启用类型级函数。

然后我补充说:

type family Mul (m :: Nat) (n :: Nat) :: Nat
type instance Mul Z     m = Z
type instance Mul (S n) m = Plus m (Mul n m)

编译给了我:

Nested type family application
  in the type family application: Plus m (Mul n m)
(Use UndecidableInstances to permit this)
In the type instance declaration for ‘Mul’

此扩展程序的名称很吓人。有些人对avoid说,并且我尝试阅读的这个扩展的解释对我来说没有意义。

在理解错误时寻找一些帮助,为什么它在这个例子中出现,在这个上下文中 undecidable 的含义是什么,在什么情况下这个扩展像它一样可怕声音?

2 个答案:

答案 0 :(得分:2)

这并不可怕。它禁用(相当弱)GHC检查,试图确定类型族和实例定义终止。因此,其最坏的情况是非终止类型检查。但是,大多数情况下我们会收到错误消息而不是实际循环,因为循环通常会超出类型检查器中的堆栈限制。我们不会得到不安全,不连贯或任何其他可能对程序稳健性或推理产生负面影响的财产。

“Undecidable”可能是一个比保证更强的表达,因为它只表示GHC无法决定定义是否终止。在许多情况下,GHC对于工作来说太弱了,而其他依赖语言的编译器也能够毫无问题地检查终止。对于GHC,UndecidableInstances通常也需要显式终止定义,在这种情况下,它的使用是非常合理的。

答案 1 :(得分:2)

UndecidableInstance可以使用。当然,你应该总是考虑片刻是否确实需要某些东西,或者选择另一条道路更为惯用。

Luke指出UndecidableInstances不应该用于实现超类。嗯,这是真的,但它与不可判断的实例并没有多大关系 - 超类只是一个黑客,而且几乎与设计抽象的方式相反。

IME 是真的,至少不再是,超级类是UndecidableInstances最常见的用法。启用此扩展程序可以做很多事情但不能没有。当然,如果你实际上希望在编译时进行图灵完全相关的打字,那么不能不能强加防止停止的条件,这基本上是什么所有DataKinds模糊都要前往。

所以,不要太担心;事实上,你可能不会绕过UndecidableInstances。正如AndrásKovács所说,这个扩展是完全安全的WRT 正确性,可能发生的最坏情况是循环/错误。

如果这对您的口味太可怕了,请使用前面设计的语言作为依赖类型和总数,即Agda