[英]Haskell type checking and determinism
根据Haskell 2010语言报告 ,其类型检查器基于Hindley-Milner 。 所以考虑这种类型的函数f
,
f :: forall a. [a] -> Int
例如,它可以是长度函数。 根据Hindley-Milner的说法, f []
类型检查Int
。 我们可以通过将f
的类型实例化为[Int] -> Int
,以及[]
到[Int]
的类型来证明这一点,然后得出应用程序([Int] -> Int) [Int]
的类型为Int
结论。
在这个证明中,我选择实例化类型forall a. [a] -> Int
forall a. [a] -> Int
和forall a. [a]
forall a. [a]
将Int
替换为a
。 我可以替代Bool
,证明也可以。 在Hindley-Milner中,我们可以将多态类型应用于另一个,而不指定我们使用的实例,这不奇怪吗?
更具体地说,Haskell中的什么阻止我在f
的实现中使用类型a
? 我可以想象f
是一个函数,在任何[Bool]
上等于18
,并且等于所有其他类型列表上的通常长度函数。 在这种情况下, f []
是18
还是0
? Haskell报告称“内核未正式指定”,因此很难说。
在类型推断期间,这样的类型变量确实可以实例化为任何类型。 这可能被视为一个非常不确定的步骤。
GHC,就其价值而言,在这种情况下使用内部Any
类型。 例如,编译
{-# NOINLINE myLength #-}
myLength :: [a] -> Int
myLength = length
test :: Int
test = myLength []
结果如下Core:
-- RHS size: {terms: 3, types: 4, coercions: 0}
myLength [InlPrag=NOINLINE] :: forall a_aw2. [a_aw2] -> Int
[GblId, Str=DmdType]
myLength =
\ (@ a_aP5) -> length @ [] Data.Foldable.$fFoldable[] @ a_aP5
-- RHS size: {terms: 2, types: 6, coercions: 0}
test :: Int
[GblId, Str=DmdType]
test = myLength @ GHC.Prim.Any (GHC.Types.[] @ GHC.Prim.Any)
GHC.Prim.Any
出现在最后一行。
现在,这真的不确定吗? 嗯,它确实涉及算法中“中间”的一种非确定性步骤,但最终得到的(最一般的)类型是Int
,并且确定性地如此。 我们为a
选择的类型无关紧要,我们总是在最后获得类型Int
。
当然,获取相同类型是不够的:我们还希望获得相同的Int
值。 我猜想,可以证明,给定
f :: forall a. T a
g :: forall a. T a -> U
然后
g @ V (f @ V) :: U
无论V
是什么类型都是相同的值。 这应该是应用于那些多态类型的参数化的结果。
为了跟进Chi的答案,这里证明f []
不能依赖于f
和[]
的类型实例。 根据定理免费( 这里的最后一篇文章),对于任何类型a,a'
和任何函数g :: a -> a'
,然后
f_a = f_a' . map g
其中f_a
是类型a
上f
的实例化,例如在Haskell中
f_Bool :: [Bool] -> Int
f_Bool = f
然后,如果你评估[]_a
上的先前相等,它会产生f_a []_a = f_a' []_a'
。 在原始问题的情况下, f_Int []_Int = f_Bool []_Bool
。
Haskell中的参数化的一些参考也是有用的,因为Haskell看起来比Walder的论文中描述的多态lambda演算更强。 特别是,这个维基页面说明了参数化可以通过使用seq
函数在Haskell中打破。
维基页面还说我的类型依赖函数存在(在其他语言中而不是Haskell),它被称为ad-hoc多态 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.