2014-03-06 76 views
1

如果編譯器推測出輸入參數的類型,爲什麼不選擇正確版本的重載方法?Math.Max上的F#類型推斷

在這個例子中爲什麼不能選擇正確的Math.Max時使用的類型正確地推斷上的元素進行比較:

let listMax = 
    List.map2 (fun l r -> Math.Max(l,r)) [2;4] [5;3]  //compile error 
let listMax2 = 
    List.map2 (fun (l:int) r -> Math.Max(l,r)) [2;4] [5;3] //no compile error  

當然你也可以只使用max函數在這的情況下,但還有很多其他方法沒有本地等價物。

回答

7

由於@Gos正確地指出,使用管道運營商可以幫助在這種情況下。原因是類型推理從左到右工作 - 所以,如果使用管線運算符,它知道其中一個輸入是整數列表,並基於此,它會選擇Math.Max的正確超載。

編譯器一般需要知道當它重載或類型時要調用成員的對象(例如,如果你想要做l.Foo()地圖功能裏面) - 因爲在這種情況下,需要知道究竟是什麼類型。

F#還定義了它自己的基本數學函數版本,它可以更好地處理類型推斷。所以,你可以用max功能(這也可以很好地直接傳遞給map2)取代Math.Max

List.map2 max [2;4] [5;3] 

這工作得更好,因爲F#並不需要執行重載解析(功能不超載)。它只是跟蹤一個特殊的通用約束條件,後來得到滿足和解決。

+0

感謝您的回答。我不太明白的是類型推斷在頂部示例中正常工作,l&r被正確識別爲int。那麼爲什麼不能在沒有訂單更改的情況下選擇正確的Max? –

+1

@FsharpPete類型推斷通過改進關於類型的一些初始知識來工作。因此,當它在第一種情況下到達「Math.Max」時,它只知道它們是(通用)類型的一些值''a''和''b'。這不足以解決'Math.Max',所以它記錄一個錯誤,然後完成處理文件的其餘部分 - 它在那裏找到列表,並將''a'和''b''改進爲'int'。在使用'max'的版本中,它的作用是因爲它增加了一個約束條件,即'a'和''b'必須支持最大限度的... –

1

我不能告訴你爲什麼,但我發現,管道運營商經常幫助的類型推斷:

let listMax = 
    [5;3] |> List.map2 (fun l r -> Math.Max(l,r)) [2;4] 
+0

這是因爲,正如在Tomas的答案中,類型推斷是從左到右。 –