Подтвердить что ты не робот

Как проверить ссылочное равенство в F #?

F # использует структурное равенство для оператора =, который почти всегда вам нужен:

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

Но в некоторых алгоритмах может быть важно спросить: "Являются ли эти две вещи одним и тем же объектом?" Это может помочь, например, определить циклы на графике. Итак, как я могу задать ссылочное равенство в F #? I.e., как написать функцию 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"
4b9b3361

Ответ 1

Ответ, оказывается, заключается в использовании 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" был задан один вопрос: короткая проверка равенства в F #? И поскольку этот вопрос вопроса почти заставил меня взглянуть прямо мимо него, я подумал, что я снова спрошу (и отвечу) на вопрос. Надеемся, что эта тема вопроса вопроса будет легче найти, когда Googling для таких терминов, как "ссылочное равенство в F #".

Как насчет obj.ReferenceEquals?

В комментарии Федор Сойкин спрашивает, что случилось с obj.ReferenceEquals. Ответ "немного", но есть два способа, в которых LanguagePrimitives.PhysicalEquality лучше, чем obj.ReferenceEquals для большинства F # -кодов:

1) PhysicalEquality выдает ошибку компилятора, когда вы передаете ему два разных типа, тогда как obj.ReferenceEquals просто принимает два obj и поэтому с радостью пытается сравнить int list с char list:

let a = [1;2;3]
let b = ['a';'b';'c']

obj.ReferenceEquals(a,b) // Returns false
LanguagePrimitives.PhysicalEquality a b // Compiler error

2) PhysicalEquality не позволит вам сравнивать типы значений, только ссылочные типы. obj.ReferenceEquals позволит вам сравнить два типа значений и неявно поместить их в первую очередь. Но он помещает каждый отдельно, что означает, что он всегда будет возвращать false, даже если вы дали ему "тот же" объект значения:

let n = 3
let n' = n
obj.ReferenceEquals(n,n') // Returns false!
LanguagePrimitives.PhysicalEquality n n' // Compiler error

И, конечно же, есть еще одно отличие, которое сводится к личным предпочтениям и простоте использования. PhysicalEquality принимает параметры в стиле карри, которые прекрасно сочетаются с типом вывода и частичным приложением. obj.ReferenceEquals принимает параметры стиля в стиле, что означает, что он немного уродливее.

По всем этим причинам LanguagePrimitives.PhysicalEquality лучше использовать почти в каждом сценарии, чем obj.ReferenceEquals.