2016-09-19 53 views
1

一個非常方便的功能是,你可以做內聯和保值型的多態性一定程度的(雖然我認爲「鴨打字」更貼切):爲什麼內聯函數的類型推斷強迫參數爲某種類型,而不是將其限制爲具有op_Explicit?在F#

// can be used with any argument that implements op_Explicit: ^a -> float 
let inline Divide a b = float a/float b 

但是當我把它擴大到被包含在某種類型中,F#推斷第一個參數爲float,即使我明確要求轉換爲浮動。我錯過了什麼,或者更好,我怎樣才能得到op_Explicit的行爲?我嘗試添加靜態成員的約束,但似乎並沒有幫助:

type XTest<'T> = 
    | Value of 'T 
    | Other of 'T 
    // a is inferred as float, b as req. op_Explicit 
    static member inline Divide a b = 
     match a with 
     | Value x -> 
      match b with 
      | Value y -> 
       let res = float x/float y 
       XTest.Value res |> Some 
      | _ -> failwith "not implemented" 

     | Other x-> Some (XTest.Other x) 

也許重要的是要注意:如果刪除Other識別聯合,它推斷出第一個參數的類型進行正確的「要求各會員op_Explicit「

回答

10

這不是因爲類型推理失敗。事實上,如果你仔細觀察,你會發現y被正確推斷爲'a (requires op_Explicit)

由於「失敗」只適用於x,但不y,讓我們來看看:如何從yx不同?

答案在最後一行:x用於構造XTest<'T>的實例。但什麼是T?很明顯,'TDivide的返回類型的泛型參數,但返回類型是什麼?

的答案位於底部的第四行:XTest.Value res。由於resfloat(分割2個float S的結果),則這意味着Divide的返回類型必須是XTest<float> option,這反過來又意味着,最後一行也必須產生XTest<float>,這意味着x必須是float

類型推斷的勝利。不是失敗。 :-)

+2

謝謝,優秀的答案,一如既往:)。它也隱含地顯示瞭解決方案。我只需要讓類型推斷知道'x'不知道是'float'類型,我通過將最後一行改爲'Some(XTest.Other(float x))'來完成。 – Abel

相關問題