2014-09-10 49 views
0

下一次測試失敗。我將GetType直接調用到函數定義中,然後我還在內聯函數中調用GetType。生成的類型不相等。比較F#中的函數類型

namespace PocTests 

open FsUnit 
open NUnit.Framework 

module Helpers = 
    let balance ing gas = ing - gas 

[<TestFixture>] 
type ``Reflected types``()= 

    [<Test>] member x. 
     ``test type equality with inline use``() = 
      let inline (=>) f = f.GetType().FullName, f in 
      let fullName, fval = (=>) Helpers.balance in 
      Helpers.balance.GetType().FullName |> should equal (fullName) 

我怎麼能得到相同的類型,以便「可比」。

回答

5

當您使用函數作爲值時,F#不會保證兩個創建的對象將是「相同的」。下封編譯器會爲每個實例的新閉包對象,所以你會真正得到false作爲結果,甚至當你嘗試這樣的事:

balance.GetType().FullName = balance.GetType().FullName 

這是預期的行爲 - 當你直接嘗試比較功能,編譯器會告訴你,功能不能滿足等式約束和無法比擬的:

> let balance ing gas = ing - gas;; 
val balance : ing:int -> gas:int -> int 

> balance = balance;; 
error FS0001: The type '(int -> int -> int)' does not support the 
'equality' constraint because it is a function type 

這意味着,最好的回答你的問題是,你要問什麼不能做。我認爲比較函數值很可能不是一個好主意,但如果您提供一些更詳細的信息來說明您爲什麼要這樣做,那麼可能對您的具體問題有更好的答案。

如果你真的想在函數值進行平等的測試,那麼可能是最清晰的方法是定義一個接口,並測試普通對象相等:

type IFunction = 
    abstract Invoke : int * int -> int 
let wrap f = 
    { new IFunction with 
     member x.Invoke(a, b) = f a b } 

現在,您可以包裝balance功能接口實現可以比較的:

let balance ing gas = ing - gas 
let f1 = wrap balance 
let f2 = f1 
let f3 = wrap balance 
f1 = f2 // These two are the same object and are equal 
f1 = f3 // These two are different instances and are not equal 
+0

我通過反射得到一個地圖,其中規格爲(函數類型,名稱args,返回類型)。此外,我正在構建一個地圖obj * string>,並選擇這些函數。我想強制執行一個約定,以確保對於同一個鍵,我得到一個與規範相對應的函數(因爲函數映射是手工製作的)。但是,如果類型不同,就像你說的那樣,這看起來不太可行。 – jruizaranguren 2014-09-10 21:48:29

+0

這對我的目的來說就足夠了如果我可以用引號將函數包裝起來以獲得名稱或簽名。但根據你在http://stackoverflow.com/questions/4944668/f-quotations-traversing-into-function-calls-represented-by-a-value中的評論,這是不可行的,除非2011年之後有一些新的黑客可用。 – jruizaranguren 2014-09-11 10:32:17

1
每次調用 Helpers.balance一個新的閉包被創建時

,所以

Helpers.balance.GetType().FullName |> printfn "%A" //output: "[email protected]" 
Helpers.balance.GetType().FullName |> printfn "%A" //output: "[email protected]" 

與像類(在C#編譯自exe文件反編譯)

[Serializable] 
internal class [email protected] : OptimizedClosures.FSharpFunc<int, int, int> 
{ 
    internal [email protected]() 
    { 
     base..ctor(); 
    } 

    public override int Invoke(int ing, int gas) 
    { 
     return Program.Helpers.balance(ing, gas); 
    } 
}