为什么我们不能在Coq / Agda / Idris中的Set / Type上进行模式匹配?

时间:2018-09-08 02:13:28

标签: coq idris agda

考虑一个接受Set并返回其字节长byteLength的函数:

byteLength : Set -> Maybe Nat

如果要直接实现此功能,则需要在类型参数上进行模式匹配:

byteLength Char = Just 1
byteLength Double = Just 8
byteLength _ = Nothing

但是上面的代码无法编译,因为不允许在Set / Type上进行模式匹配。

所以我们必须将接口定义为解决方法

Interface ByteLength a where
    byteLength : Nat

implement ByteLength Char where
    byteLength = 1

,并且以更一般的方式,也许我们可以使用TypeRep之类的东西来对TypeRep进行类似的操作和模式匹配。但是TypeRep也被定义为接口。

我认为使用接口和使用forall有很大的不同,因为接口表示“针对某些类型”,而forall表示“针对所有类型”。

我想知道为什么这些DT语言不支持Set / Type上的模式匹配,还有一些我不知道的特殊原因吗?

1 个答案:

答案 0 :(得分:7)

在Agda,Idris,Haskell和许多其他语言中,对类型的量化是 parametric (与 ad-hoc多态性相对,在该类型中您可以匹配类型) 。从实现的角度来看,这意味着编译器可以从程序中删除所有类型,因为函数永远不能在计算上依赖类型Set的参数。在类型依赖的语言中,能够删除类型尤其重要,因为类型通常会变成巨大的表达式。

从理论上讲,参数多态性很好,因为它允许我们仅通过查看函数的类型(雄辩地称为"free theorems" by Phil Wadler)就可以推断出函数的某些属性。我可以尝试为您提供本文的要旨,但您实际上应该去阅读它。

当然,有时需要临时多态性才能实现功能,这就是Haskell和Idris具有 type类的原因(Agda具有类似的功能,称为 instance arguments ,并且Coq具有规范结构和类型类)。例如,在Agda中,您可以定义如下记录:

record ByteLength (A : Set) : Set where
  field
    theByteLength : Nat
open ByteLength

byteLength : (A : Set) {{_ : ByteLength A}} -> Nat
byteLength A {{bl}} = bl .theByteLength

然后您可以通过定义实例来为各种类型定义byteLength函数:

instance
  byteLengthChar : ByteLength Char
  byteLengthChar .theByteLength = 1

  byteLengthDouble : ByteLength Double
  byteLengthDouble .theByteLength = 8

使用此代码,byteLength Char的计算结果为1,而byteLength Double的计算结果为8,但对于其他任何类型的类型,都会引发类型错误。