2014-09-10 52 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); 
    } 
}