проверка равенства в F #? - PullRequest
5 голосов
/ 22 апреля 2010

В F # оператор равенства (=) обычно является экстенсиональным, а не интенсиональным. Замечательно! К сожалению, мне кажется, что F # не использует равенство указателей для сокращения этих расширенных сравнений.

Например, этот код:

type Z = MT | NMT of Z ref

// create a Z:
let a = ref MT
// make it point to itself:
a := NMT a

// check to see whether it's equal to itself:
printf "a = a: %A\n" (a = a)

... дает мне большую ошибку сегментации жира [*], несмотря на то, что 'a' и 'a' оба оценивают одну и ту же ссылку. Это не так здорово. Другие функциональные языки (например, схема PLT) получают это право, используя консервативное сравнение указателей, чтобы возвращать «истину», когда это можно определить с помощью сравнения указателей.

Итак: я приму тот факт, что оператор равенства F # не использует сокращения; Есть ли способ выполнить интенсиональную (основанную на указателе) проверку на равенство? Оператор (==) не определен в моих типах, и я хотел бы, чтобы кто-нибудь сказал мне, что он каким-то образом доступен.

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

[*] Это может быть переполнение стека в Windows; В Моно есть вещи, которые мне не нравятся ...

1 Ответ

7 голосов
/ 22 апреля 2010

Есть два варианта, которые мне известны. Стандартный подход .NET будет использовать System.Object.ReferenceEquals. Немного лучшим подходом в F # может быть использование LanguagePrimitives.PhysicalEquality, которое в основном идентично, но работает только со ссылочными типами (что, вероятно, правильно для ваших целей) и требует, чтобы оба аргумента имели одинаковый статический тип. Вы также можете определить пользовательский оператор по своему выбору в терминах любой из этих функций, если вам нужен более приятный синтаксис.

Кроме того, в .NET я получаю бесконечный цикл, но не переполнение стека, когда я запускаю ваш код, предположительно из-за оптимизации хвостового вызова.

...