考虑一个接受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上的模式匹配,还有一些我不知道的特殊原因吗?
答案 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
,但对于其他任何类型的类型,都会引发类型错误。