【发布时间】:2018-08-10 11:15:41
【问题描述】:
根据Haskell 2010 language report,其类型检查器基于Hindley-Milner。所以考虑这个类型的函数f,
f :: forall a. [a] -> Int
例如可以是长度函数。根据 Hindley-Milner 的说法,f [] 类型检查为Int。我们可以通过将f 的类型实例化为[Int] -> Int,将[] 的类型实例化为[Int] 来证明这一点,然后得出应用程序([Int] -> Int) [Int] 的类型为Int 的结论。
在这个证明中,我选择通过将Int 替换为a 来实例化类型forall a. [a] -> Int 和forall a. [a]。我可以用Bool 代替,证明也有效。在 Hindley-Milner 中我们可以将多态类型应用于另一个,而不指定我们使用哪些实例,这不是很奇怪吗?
更具体地说,Haskell 中的什么阻止我在 f 的实现中使用 a 类型?我可以想象f 是一个等于任何[Bool] 上的18 的函数,并且等于所有其他类型列表上的通常长度函数。在这种情况下,f [] 会是 18 还是 0 ? Haskell 报告说“内核没有正式指定”,所以很难说。
【问题讨论】:
-
这是个好问题。请注意,由于 参数化,您的函数
f在[Bool]上的行为与在其他列表类型[a]上的行为不同,因此不能存在(即不能用 Haskell 编写)。在 Haskell 中,无法编写if a==Bool then ...并拥有未更改的签名forall a. [a] -> Int。 -
在下面查看我的答案。参数化一开始可能有点难以理解,但您可以从 Wadler 的经典“免费定理”论文开始,其中展示了很好的示例。
-
我没有完美的参考。参数化有时会受到底部的影响(
seq,无限递归),但我记得假设函数严格,仍然可以具有较弱的参数化形式。 (同样,我无法提供参考)。要完全“打破”参数性,可以使用forall a. Typeable a => [a] -> Int,它允许if a==Bool then ...——但这里类型发生了变化,所以它并没有真正被打破:我们有一种用于参数多态性的类型,另一种用于临时(非参数)多态性。 -
不,在 Haskell 中根本不需要额外的
a参数。即使在 Coq 中,您也无法消除(a : Type),因此没有“如果”。在 Coq 中,您需要一些参数来消除,例如forall (a : Type), typeable a -> list a -> int其中typeable a被适当定义,例如带有归纳定义。 -
@chi 没有额外的
a,我发现最好的是f l = if typeOf l == typeOf ([True]) then 18 else length l。但随后f []因类型错误而崩溃。你有别的看法吗?