[英]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.