如何检查F#中的引用相等性?

时间:2016-08-30 00:27:19

标签: f# equality

F#对=运算符使用结构相等,这几乎总是你想要的:

let a = [1; 2; 3]
let b = [1; 2; 3]
printfn "%A" (a = b)  // Prints "true"

但是在某些算法中,能够提出这两个事物是同一个对象是非常重要的吗?"例如,这可以帮助检测图中的循环。那么我如何在F#中要求引用相等?即,如何编写下面的isSameObject函数?

let isSameObject x y = ???
let a = [1; 2; 3]
let b = [1; 2; 3]
let a' = a
printfn "%A" (isSameObject a b)  // Prints "false"
printfn "%A" (isSameObject a a')  // Prints "true"

1 个答案:

答案 0 :(得分:40)

事实证明,答案是使用LanguagePrimitives.PhysicalEquality

let isSameObject = LanguagePrimitives.PhysicalEquality
let a = [1; 2; 3]
let b = [1; 2; 3]
let a' = a
printfn "%A" (isSameObject a b)  // Prints "false"
printfn "%A" (isSameObject a a')  // Prints "true"

我可以在Stack Overflow上找到一个问题: short-cutting equality checking in F#?由于那个问题的主题几乎让我一目了然,我想我会再问(并回答)这个问题。希望这个问题的主题行能够更容易地找到谷歌搜索术语,例如" F#"中的参考平等。

obj.ReferenceEquals怎么样?

在评论中,Fyodor Soikin询问obj.ReferenceEquals的错误。答案是"并不多",但对于大多数F#代码,LanguagePrimitives.PhysicalEquality有两种方式优于obj.ReferenceEquals

1)PhysicalEquality在传递两种不同类型时会抛出编译错误,而obj.ReferenceEquals只需要两个obj,因此很乐意尝试将int listchar list进行比较let a = [1;2;3] let b = ['a';'b';'c'] obj.ReferenceEquals(a,b) // Returns false LanguagePrimitives.PhysicalEquality a b // Compiler error

PhysicalEquality

2)obj.ReferenceEquals不允许您比较值类型,只比较引用类型。 let n = 3 let n' = n obj.ReferenceEquals(n,n') // Returns false! LanguagePrimitives.PhysicalEquality n n' // Compiler error 将允许您比较两种值类型,并将隐式地将它们打包。但是它会分别对每一个进行包装,这意味着即使你给它的同时也会总是返回错误#34;价值对象:

PhysicalEquality

当然,还有另一个不同之处,可归结为个人偏好和易用性。 obj.ReferenceEquals采用curried风格的参数,可以很好地与类型推断和部分应用程序配合使用。 LanguagePrimitives.PhysicalEquality采用了tupled风格的参数,这意味着使用它会稍微有点难看。

由于所有这些原因,obj.ReferenceEquals最好在几乎每种方案中使用,而不是msbuild /p:Configuration=Release /p:OSGroup=Windows_NT /p:Performance=true