gpt4 book ai didi

带有函数案例的联合类型的 F# 相等行为

转载 作者:行者123 更新时间:2023-12-02 08:08:51 24 4
gpt4 key购买 nike

我试图理解这种平等行为。记录相等性测试失败,但记录唯一属性的相等性测试通过。这是一个错误吗?或者有人可以解释这种行为吗?

type TestUnion =
| Case1
| Case2 of (int -> string)

type TestType =
{
Foo : TestUnion
}

open Microsoft.VisualStudio.TestTools.UnitTesting

[<TestClass>]
public Testing() =

let a = { Foo = Case1 }
let b = { Foo = Case1 }

[<TestMethod>]
member __.ThisFails () =
Assert.AreEqual(a, b)

[<TestMethod>]
member __.ThisPasses () =
Assert.AreEqual(a.Foo, b.Foo)

我知道它失败的原因是因为其中一种情况是函数。如果我将其更改为一个简单的值,则两个测试都会通过。但令我感到奇怪的是,a) 相等根本失败,因为使用了没有值的简单情况,并且 b) 当属性相等通过时,记录相等失败。

注意:当其他简单属性也存在时,记录相等性将失败。 IOW,联合类型毒害整个记录的相等性,即使联合类型属性测试为相等。

最佳答案

Assert.AreEqual方法试图变得聪明,当然失败了。给定两个对象,此方法将做的第一件事是测试引用相等性:obj.ReferenceEquals( Case1, Case1 ) .这立即起作用,因为所有 Case1值是同一个对象。

现在,如果 Assert.AreEqual的参数不是同一个对象,它会继续调用 obj.Equals .为您记录,执行Equals将始终返回 false,因为 F# 编译器没有为其实现相等。为什么?因为某些字段的类型(即 TestUnion )不相等。为什么不TestUnion有平等吗?因为它至少有一个类型不相等的情况 - 即 int -> string .

如果您更改 Case1类似于 Case1 of int然后尝试 Assert.AreEqual( Case1 42, Case1 42 ) ,测试将失败。这会发生,因为 Case1 42 的两个实例化将不再是同一个对象(除非您进行优化编译),并且 Equals TestUnion 的实现将始终返回 false。

如果你真的想让它起作用(并且你真的知道如何比较函数),你总是可以实现 Equals你自己:

[<CustomEquality; NoComparison>]
type TestType = { Foo: TestUnion }
with
override this.Equals other = (* whatever *)
override this.GetHashCode() = (* whatever *)

请注意,要完成此操作,您必须花很多功夫:您必须添加 CustomEqualityNoComparison (或 CustomComparison )属性,并实现 GetHashCode .如果您不这样做,编译器会提示您对等式的实现不一致。

然而,“正确”的解决方案是始终尽可能多地使用 F# 工具。在这种特定情况下,这意味着使用 =比较运算符:
Assert.IsTrue( Case1 = Case1 )

这样,如果你遗漏了什么,编译器总是会告诉你:
Assert.IsTrue( a = b )
// The type 'TestType' does not support the 'equality' constraint because blah-blah-blah

F# 编译器通常比底层 .NET CLR 更正确和一致。

关于带有函数案例的联合类型的 F# 相等行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48941343/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com