爲什麼這個說法給我一個類型不匹配錯誤,瞭解類型不匹配錯誤?
let x = List.rev [] in (3::x, true::x);;
而這種說法不?
let x = [] in (3::x, true::x);;
我猜想這是因爲x被給出的第一條語句的函數調用,而它僅在第二條語句給一個空列表。但是,我不確定爲什麼第二個工作,第一個不工作?任何幫助都感激不盡。謝謝!
爲什麼這個說法給我一個類型不匹配錯誤,瞭解類型不匹配錯誤?
let x = List.rev [] in (3::x, true::x);;
而這種說法不?
let x = [] in (3::x, true::x);;
我猜想這是因爲x被給出的第一條語句的函數調用,而它僅在第二條語句給一個空列表。但是,我不確定爲什麼第二個工作,第一個不工作?任何幫助都感激不盡。謝謝!
嘗試以下操作:
let x = [] ;;
結果:val x : 'a list
。 F#知道x
是一個尚未知類型的列表。如果它有任何內容,它的類型將是已知的。這工作得很好。
不過,下列措施不工作:
let x = List.rev [] ;;
結果:
錯誤FS0030:值限制。值「X」已經被推斷爲有通用型
val x : '_a list
要麼定義「X」作爲一個簡單的數據來看,使它成爲一個功能有明確的參數,或者,如果你不打算爲它是通用的,添加一個類型註釋。
在F#的「值約束」的錯誤可能是很難理解 - 爲什麼[]
時,允許List.rev []
是不是? - 但this article進入一些細節。從本質上講,F#總能感到安全作出功能通用的,但它只能感到安全作出值通用如果以下兩個條件:
let
的右手邊的表達式是純值,例如它沒有副作用, 和let
的右手側的表達式是不可改變。當表達式是[]
,那麼F#知道,這是一個純粹的,不可變的值,所以它可以使它通用('a list
)。但是當表達式爲someFunction []
時,F#編譯器不知道要做什麼someFunction
。儘管在這種情況下,我們知道List.rev
是標準庫的一部分,並且匹配那兩種情況,F#編譯器不能知道。像Haskell這樣的完全純語言,你可以從函數的類型簽名中知道它是純粹的,但F#是一種更實用的語言。所以F#採取保證安全的方法,不是使List.rev []
通用的結果。
因此,當你寫let x = [] in (3::x, true::x)
,該[]
值是通用空列表,所以它可以成爲一個既或int list
根據需要bool list
。但是當你編寫let x = List.rev [] in (3::x, true::x)
時,F#不能使List.rev []
通用。它可以說「這是一個我還不知道的類型的列表」,並等待類型變得清晰。然後,使用此列表的特定類型的第一個表達式(在本例中爲3::x
)將「鎖定」該列表的類型。即,F#不能認爲這個列表是通用的,所以現在已經發現這個空列表是一個空列表int
s。然後,當您嘗試將bool
附加到空的int list
時,那是一個錯誤。
如果將元組翻轉過來以使其爲true::x, 3::x
,那麼類型錯誤也會「翻轉」:它會預計bool list
並找到int list
。
所以這個答案的簡短版本是:你正在達到F#值限制,儘管這並不是很明顯,因爲你得到的錯誤根本沒有提到數值限制。
請參閱Understanding F# Value Restriction Errors以獲得對價值限制的良好討論,包括您通常會看到的最常見的地方(部分應用函數)。