【问题标题】:testing equality with Dicriminated union in a list用列表中的区分联合测试相等性
【发布时间】:2016-06-14 05:04:36
【问题描述】:

我定义了不同的类型:

type TypeNull() = class end

type MyType1 = {
    a:int;
    b:int
}

type MyType2 = {
    a:string;
    b:int
}

type MyType3 = {
    a:string;
    b:DateTime
}

以及使用它们的不同的有区别的工会:

type myDU =
    | A of int
    | B of string
    | C of string

type myDU2 =
    | D of MyType1
    | E of MyType2
    | F of TypeNull

我有将 myDU 映射到 myDU2 的函数:

let applyArray = function
    | A x -> [E({a="1"; b=2})]
    | B x -> [D({a=1; b=2});E({a="1"; b=2});E({a="5"; b=24})]
    | C x -> [D({a=1; b=2});E({a="1"; b=2});F(TypeNull())]

然后是两个测试来测试相等性:

let arrayValueEquals =
    let expected = [D({a=1; b=2});E({a="1"; b=2});E({a="5"; b=24})]
    let actual = applyArray <| B("xxx")
    actual = expected

let arrayValueNullEquals =
    let expected = [D({a=1; b=2});E({a="1"; b=2});F(TypeNull())]
    let actual = applyArray <| C("xxx")
    actual = expected

fsi 给出的内容:

val applyArray : _arg1:myDU -> myDU2 list
val arrayValueEquals : bool = true
val arrayValueNullEquals : bool = false

我的问题如下,为什么第一次测试成功,第二次失败?

这里是完整的要点:

// Learn more about F# at http://fsharp.net. See the 'F# Tutorial' project
// for more guidance on F# programming.

#load "Library1.fs"
open test2
open System

type TypeNull() = class end

type MyType1 = {
    a:int;
    b:int
}

type MyType2 = {
    a:string;
    b:int
}

type MyType3 = {
    a:string;
    b:DateTime
}

type myDU =
    | A of int
    | B of string
    | C of string

type myDU2 =
    | D of MyType1
    | E of MyType2
    | F of TypeNull

let applyArray = function
    | A x -> [E({a="1"; b=2})]
    | B x -> [D({a=1; b=2});E({a="1"; b=2});E({a="5"; b=24})]
    | C x -> [D({a=1; b=2});E({a="1"; b=2});F(TypeNull())]

let arrayValueEquals =
    let expected = [D({a=1; b=2});E({a="1"; b=2});E({a="5"; b=24})]
    let actual = applyArray <| B("xxx")
    actual = expected

let arrayValueNullEquals =
    let expected = [D({a=1; b=2});E({a="1"; b=2});F(TypeNull())]
    let actual = applyArray <| C("xxx")
    actual = expected

【问题讨论】:

  • 您是否打印出actual 的值来查看它是什么?我怀疑 TypeNull() 不是你想象的那样。或者您是否尝试将预期和实际发送到 F# Interactive 以查看类型。
  • 它确实给了我:> TypeNull();;验证它:TypeNull = FSI_0002+TypeNull
  • > 让实际 = applyArray

标签: f# equality discriminated-union


【解决方案1】:

在 F# 中有一个叫做 Structural Equality 的东西。

简而言之:如果列表、数组和可区分联合的元素确实支持相等,则它们支持相等。对于列表,它将是逐个元素的比较。

基本可区分联合支持开箱即用的平等,但对象不支持,这就是为什么一旦将 TypeNull 添加到列表中,比较就会失败。

试试这个:

type TypeNull() = class end
TypeNull() = TypeNull() // false

然后

let actual = TypeNull()
let expected = TypeNull()
actual = expected // false

所以,除非你为你的对象明确定义相等,否则默认行为是只有当两个实例相同时才会产生 true:

type TypeNull() = class end
let a = TypeNull()
let actual = a
let expected = a
actual = expected // true

但对于 DU,它会自动运行:

type TypeNull = TypeNull
TypeNull = TypeNull // true

然后

let actual = TypeNull
let expected = TypeNull
actual = expected // True

【讨论】:

  • 我使用 type a() = class end 来“模拟” type a = {}。所以不一样?
  • 是的,但在 F# 中,这不是一个有区别的联合。这是一个简单的对象。如果实例相同,则默认情况下对象相等。在 C# 中也是如此。
  • 今晚你告诉我的我会好好考虑的……我得好好想想。有些东西我不明白,但这是一天的结束,所以..
  • 好的,将type TypeNull() 更改为type TypeNull = TypeNull,然后从实例中删除()。它应该可以工作。
  • 模拟“空记录”的方法是单例区分联合,就像在古斯塔沃的例子中一样。
猜你喜欢
  • 1970-01-01
  • 2020-04-30
  • 1970-01-01
  • 2021-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-05
相关资源
最近更新 更多