[英]How can eta-reduction of a well typed function result in a type error?
我正在玩van Laarhoven鏡頭並遇到一個問題,其中類型檢查器拒絕了et-reduced形式的良好類型的功能:
{-# LANGUAGE RankNTypes #-}
import Control.Applicative
type Lens c a = forall f . Functor f => (a -> f a) -> (c -> f c)
getWith :: (a -> b) -> ((a -> Const b a) -> (c -> Const b c)) -> (c -> b)
getWith f l = getConst . l (Const . f)
get :: Lens c a -> c -> a
get lens = getWith id lens
上面的類型檢查,但如果我eta-reduce get
get :: Lens c a -> c -> a
get = getWith id
然后GHC(7.4.2)抱怨說
Couldn't match expected type `Lens c a'
with actual type `(a0 -> Const b0 a0) -> c0 -> Const b0 c0'
Expected type: Lens c a -> c -> a
Actual type: ((a0 -> Const b0 a0) -> c0 -> Const b0 c0)
-> c0 -> b0
In the return type of a call of `getWith'
In the expression: getWith id
我可以理解,如果函數沒有明確的類型簽名,那么結合單同性限制的eta-reduction可能會混淆類型推斷,特別是當我們處理更高級別的類型時,但在這種情況下我不是確定發生了什么。
是什么導致GHC拒絕eta減少形式,這是GHC中的錯誤/限制或更高等級類型的一些基本問題?
我要說的原因不在於η-減少本身,問題在於使用RankNTypes
你會丟失主要類型和類型推斷。
高階排序類型推斷的問題是在推斷遵循規則的λx.M
的類型時
Γ, x:σ |- M:ρ
----------------------
Γ |- λx:σ.M : σ→ρ
我們不知道我們應該為x
選擇什么類型的σ。 在Hindley-Milner類型系統的情況下,我們將自己限制為x
類型 - 量詞 - 無類型,並且推理是可能的,但不是任意排序類型。
因此,即使使用RankNTypes
,當編譯器遇到沒有顯式類型信息的術語時,它會轉向Hindley-Milner並推斷出它的rank-1主體類型。 但是,在您的情況下, getWith id
所需的類型是rank-2,因此編譯器無法自行推斷它。
你的明確案例
get lens = getWith id lens
對應於已經明確給出x
的類型λ(x:σ).Mx
。 在類型檢查getWith id lens
之前,編譯器知道lens
類型。
在減少的情況下
get = getWith id
編譯器必須自己推斷getWidth id
的類型,因此它堅持使用Hindley-Milner並推斷出rank-1類型不足。
實際上它非常簡單:GHC推斷每個表達式的類型,然后開始將它們統一在=
。 當只有rank-1類型時,這總是很好,因為選擇了最多態的(這是明確定義的); 所以任何可能的統一都會成功。
但它不會選擇更一般的rank-2-type,即使這是可能的,所以getWith id
被推斷為((a -> Const aa) -> c -> Const ac) -> (c -> a)
,而不是(forall f . Functor f => (a -> fa) -> c -> fc) -> (c -> a)
。 我想如果GHC確實做了這樣的事情,傳統的1級類型推斷就不再適用了。 或者它永遠不會終止,因為不存在一個明確定義的最多態的rank-n類型。
這並沒有解釋為什么它不能從get
的簽名中看到它需要在這里選擇排名-2,但可能也有一個很好的理由。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.