Тестирование равенства с Dicricted union в списке

Я определил различные типы:

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

Который в ФСИ дает:

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

1 ответ

Решение

В F# есть нечто, называемое структурным равенством.

Вкратце: списки, массивы и Дискриминационные союзы поддерживают равенство, если их элементы поддерживают равенство. Для списков это будет поэлементное сравнение.

Основные Дискриминационные Союзы поддерживают Равенство из коробки, а объекты - нет, и поэтому после добавления 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
Другие вопросы по тегам