[英]Code unexpectedly accepted by GHC/GHCi
我不明白为什么这段代码应该通过类型检查:
foo :: (Maybe a, Maybe b)
foo = let x = Nothing in (x,x)
由于每个组件都绑定到相同的变量x
,所以我希望此表达式的最通用类型是(Maybe a, Maybe a)
。 如果使用where
而不是let
我将得到相同的结果。 我想念什么吗?
简而言之, x
的类型由let
推广。 这是Hindley-Milner类型推断算法中的关键步骤。
具体来说, let x = Nothing
最初为x
分配类型Maybe t
,其中t
是新鲜的类型变量。 然后,对类型进行泛化,通用地量化其所有类型变量(技术上:除了在其他地方使用的变量,但这里我们只有t
)。 这导致x :: forall t. Maybe t
x :: forall t. Maybe t
。 请注意,此类型与Nothing :: forall t. Maybe t
完全相同Nothing :: forall t. Maybe t
Nothing :: forall t. Maybe t
。
因此,每次我们在代码中使用x
时,它都表示可能不同的类型Maybe t
,就像Nothing
一样。 因此,使用(x, x)
与(Nothing, Nothing)
类型相同。
相反,lambda 不具有相同的概括步骤。 相比之下(\\x -> (x, x)) Nothing
“ only”的类型为forall t. (Maybe t, Maybe t)
forall t. (Maybe t, Maybe t)
,其中两个组件都被强制为相同类型。 在这里x
再次被赋予类型Maybe t
,其中t
fresh,但是没有被概括。 然后(x, x)
被分配类型(Maybe t, Maybe t)
。 仅在最高级别上,我们才一般性地加上了forall t
,但是在这一点上太晚了,无法获得异构对。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.