2016-06-14 83 views
6

我在編寫結果類型和各種函數時遇到了問題,並遇到了我無法解釋的類型不匹配錯誤。下面是一個最小的例子:結果類型中的類型不匹配錯誤

type ('a, 'b) result = 
    | Success of 'a 
    | Failure of 'b list 

let apply fr xr = 
    match fr, xr with 
    | Success f, Success x -> Success (f x) 
    | Failure _, Success _ -> fr 
    | Success _, Failure _ -> xr 
    | Failure a, Failure b -> Failure (List.concat [a; b]) 

編譯此代碼產生以下錯誤:如果您更改按照以下申請功能

init.fsx(8,31): error FS0001: Type mismatch. Expecting a 
('a,'b) result 
but given a 
(('c -> 'a),'d) result 
The resulting type would be infinite when unifying ''a' and ''b -> 'a' 

,它編譯正確:

let apply fr xr = 
    match fr, xr with 
    | Success f, Success x -> Success (f x) 
    | Failure a, Success _ -> Failure a 
    | Success _, Failure b -> Failure b 
    | Failure a, Failure b -> Failure (List.concat [a; b]) 

爲什麼使用匹配的超值(這裏是frxr)無法正常工作,但構建新的失敗值呢?

回答

4

關鍵一點需要了解函數的結果是,該類型一個受到歧視的工會關注其所有案件。即使您僅「重複使用來自函數參數Failure的實例作爲返回值,全部返回值,包括Success的情況下,必須具有與此參數相同的類型。

因此,使用frxr作爲返回值將其類型限制爲與apply的返回類型相同。

但也有一條線將Success f的參數設置爲返回值Success (f x)!如果這兩個類型相同,f x的類型必須是f的類型!無論您應用了多少次,該函數都會返回它自己類型的函數;這種無限類型是不允許的,並導致編譯器錯誤。

通過構建返回值的新實例,允許apply的返回類型與其參數類型不同。然後,編譯器可以給出f及其返回值的不同類型,避免無限函數類型。

2

這是錯誤。

在這一行:

Success f, Success x -> Success (f x) 

定義'a是一個函數類型,因此你的回報'a也是一個函數。

但是當你做

| Failure _, Success _ -> fr 

fr具有相同的功能類型,但這裏是未覈銷。

相反,創建新的對象,給它一個新的類型,可以使用的事實,成功的類型現在是在第二種情況下

+0

謝謝約翰。目前還不清楚爲什麼第一場比賽可以替代 '| |成功f,成功x - >成功(f x)' 應該對第二場比賽有任何影響 '| |失敗_,成功_ - > fr' 對我來說聽起來像編譯器中不必要的限制... – dumetrulo

+0

問題是'fr'與'Success(fx)'具有不同的類型,並且表達式需要返回變量相同的類型。 –