任何人都知道這段代碼的問題是什麼?F#:有人可以解釋我的編譯器錯誤嗎?
let rec Foo(a,b) =
match a() with
| None -> Some(b)
| Some(c) -> Some(Foo(c,b))
這裏的編譯器錯誤:「類型不匹配期待‘一個,但給定一個‘一個選項統一‘’A’和'一個選項’時,得到的類型將是無限的」
任何人都知道這段代碼的問題是什麼?F#:有人可以解釋我的編譯器錯誤嗎?
let rec Foo(a,b) =
match a() with
| None -> Some(b)
| Some(c) -> Some(Foo(c,b))
這裏的編譯器錯誤:「類型不匹配期待‘一個,但給定一個‘一個選項統一‘’A’和'一個選項’時,得到的類型將是無限的」
讓我們嘗試重現編譯器如何嘗試在此處推斷類型。
let rec Foo(a,b) =
match a() with
| None -> Some(b)
| Some(c) -> Some(Foo(c,b))
「好了,我看到a()
。a
必須是一個函數從unit
某種類型的,我不知道是哪一個呢。我把它叫做'a
。」
a : unit -> 'a
「的a()
結果與None
/Some
圖案相匹配。因此'a
必須是'b option
和c
具有類型'b
」。 (同樣,'b
代表未知的類型)。
a : unit -> 'b option
с : 'b
「沒有函數或方法被稱爲上b
(除Some
,不縮小類型下來,Foo
,其中我們不知道迄今爲止的類型)。我將表示其鍵入'c
「。
a : unit -> 'b option
b : 'c
c : 'b
「Foo
回報Some(b)
的分支之一,因此,返回類型必須是'c option
。「
Foo : (unit -> 'b option) * 'c -> 'c option
」我完成了嗎?不,我需要檢查表達式中的所有類型是否有意義。讓我們看看,在Some(c)
的情況下,返回Some(Foo(c,b))
。所以Foo(c,b) : 'c
。由於Foo
返回option
,我知道'c
對於某些'd
和b : 'd
必須是'd option
。等等,我已經有b : 'c
,也就是b : 'd option
。 'd
和'd option
必須是相同的類型,但這是不可能的!定義中必須有錯誤。我需要報告它。「所以它的確如此。」
非常好的分解,換句話說,編譯器在'a和'選項選項選項選項選項等選項之間被撕掉了。 – YotaXP 2009-12-30 13:50:02
您正在使用a()
作爲Foo
中第一個參數的選項,但最後一行c
是一種類型,但您將其傳遞給遞歸調用。
這就是導致錯誤的原因。
你會想要c
是一個選項類型。
它總是有助於逐步打破一切。如書面所示,Foo的類型爲:
val Foo : (unit -> 'a option) * 'b -> 'b option
活動模式中的每個表達式必須評估爲相同類型。在你表達的第一個模式匹配的類型爲:
'b option
因此,其他的模式也必須求'b option
或'a option
。你在這裏的方式,它返回'a option option
。
這是一個奇特的功能,但您可以通過返回第二個模式匹配中的任何選項值來糾正編譯器錯誤。這裏是我能想到的唯一例子,看起來像上面那樣:
let Foo2(a,b) =
match a() with
| None -> Some(b)
| c -> c
HTH。
_As written_,'Foo'沒有這種類型,並且實際上沒有任何其他類型;這就是錯誤的要點! – 2009-12-29 12:34:09
我理解你的觀點,但是我從Visual Studio中的F#解釋器中複製了該簽名。是的,代碼不會按照所示進行編譯或運行,但是F#確實對它做了很大的努力=) – 2009-12-29 13:01:26
只是爲了方便,你究竟要做什麼*可能有人會建議一種更好的方式來編寫你的功能 – Juliet 2009-12-29 01:24:53
@Juliet - 我不覺得舒服進入一個更好的方式來寫功能而不知道,但是,直到你提到它,我沒有想到我因爲缺乏理解而停下來的事實。 – 2009-12-29 02:01:44