Встроенное сравнение размеченных объединений в f #

Отвечая на этот вопрос, я обнаружил следующее поведение compare о дискриминируемых союзах.

type T = A | B | C | D 
compare A B   (* val it : int = -1 *)
compare A C   (* val it : int = -2 *)
compare A D   (* val it : int = -3 *)

Меня это удивило.

Могу ли я положиться на compare измерение "расстояния" между конструкторами, подобными этому?

В спецификации говорится (стр. 154) о сгенерированном compareTo:

Если T является типом объединения, вызовите Microsoft.FSharp.Core.Operators.compare сначала для индекса вариантов объединения для двух значений, а затем для каждой соответствующей пары полей x и y для данных, переносимых случаем объединения. Вернуть первый ненулевой результат.

Исходя из этого, я ожидаю, что compare для типа T всегда будет давать одно из -1,0,1, поскольку именно так compare ведет себя с числовыми типами. (Правильно?)


person Søren Debois    schedule 14.03.2014    source источник
comment
Некоторые числовые типы реализуют CompareTo(other) как (this - other), например ((short)2).CompareTo((short)5) возвращает -3.   -  person Lee    schedule 15.03.2014
comment
@Lee - это интересный момент, но, как ни странно, он не относится к функции compare в F #. Например, 2s.CompareTo(5s) возвращает -3, как вы говорите, но compare 2s 5s возвращает только -1.   -  person Tomas Petricek    schedule 15.03.2014


Ответы (1)


В цитате из спецификации говорится, что сгенерированное сравнение будет сначала сравнивать теги (по сути, это индекс конструкторов), но я не уверен, что это дает вам какую-либо полезную информацию, потому что если union несет какое-то значение, вы не узнаете, является ли число расстоянием между конструкторами или результатом сравнения содержащихся значений. Например:

type Tricky() = 
  interface System.IComparable with
    override x.CompareTo(b) = -2

type DU = 
 | A of Tricky
 | B 
 | C

// Returns -2 because of the distance between constructors
compare (A (Tricky())) C
// Returns -2 because of the comparison on `Tricky` objects
compare (A (Tricky())) (A(Tricky()))

Если вы хотите полагаться на способность определять расстояние между конструкторами, может быть безопаснее использовать перечисления:

type DU = 
 | A = 1
 | B = 2 
 | C = 3

Затем вы можете получить расстояние, преобразовав значения в целые числа с помощью (int DU.A) - (int DU.C).

person Tomas Petricek    schedule 15.03.2014