Почему "эк?" оценивать как ложное в следующем контексте, но верно ли в противном случае? - PullRequest
0 голосов
/ 29 апреля 2018

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

> (eq? 'leet 'leet)
#t
> (eq? 'let 'notleet)
#f

По какой-то причине, сравнивая первый элемент двух списков, я получаю false, даже если они равны.

> (eq? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f)))
#f

Почему это оценивается как ложное, когда я в основном сравниваю одни и те же вещи?

Ответы [ 3 ]

0 голосов
/ 29 апреля 2018

Выражение 'expression является сокращением для (quote expression). Когда выражение оценивается, оно оценивается как expression как структура данных или атомарное значение. Важно знать, что ничего в expression не оценивается дальше. Таким образом, ''x, то есть (quote (quote x)), становится списком (quote x).

eq? используется для сравнения одного и того же объекта. Это значит:

(eq? (list 'leet) (list 'leet)) ; ==> #f

Теперь оба аргумента выглядят как (leet), но два списка находятся в разных местах памяти компьютера и поэтому не совпадают.

Константы, такие как "string" и '(some list), могут создаваться один раз, а затем на них ссылаются несколько раз, но в другой реализации константы могут создаваться заново для каждого местоположения в коде. Таким образом:

(eq? "test" "test")   ; ==> #t or #f
(eq? '(leet) '(leet)) ; ==> #t or #f

В вашем коде у вас есть избыток ', поэтому (first '('leet 'a 'f)) - это на самом деле данные (quote leet), список из двух символов. Таким образом, вы применяете то же самое, что и последнее выражение выше, и вы можете ожидать #f от некоторых реализаций и #t от нескольких других. Сравнение списков не то же самое, что сравнение символов.

Так что вы можете это исправить, удалив лишние '. Тогда я предполагаю, что вы не пытались составить списки (quote leet).

(eq? (first '(leet a f)) (first '(leet coder a f f)))
; ==> #t

Если вы хотите сравнить списки, вы должны использовать equal?:

(equal? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f)))
; ==> #t

И знайте, что (first '('leet 'a 'f)) в #lang racket REPL печатает ''leet с двумя '. Первый ' - это забавный способ печати значений, который оценивается как значение, которое он должен был напечатать, и, возможно, источник этой путаницы, а второй - индикатор того, что у вас есть список (quote leet), но многие схемы его сокращают. до 'leet.

0 голосов
/ 03 мая 2018

Ответ Сильвестра правильный и подробный, но я хочу показать TL / DR; здесь:

Не используйте eq?. Вместо этого используйте equal?.

Это вся история? Нет, конечно нет. Но если вы ищете однострочную оболочку в своем мозгу, она должна быть именно этой; equal? почти всегда делает то, что вы хотите, а eq? часто нет.

0 голосов
/ 29 апреля 2018

когда я в основном сравниваю одни и те же вещи

Ты нет. (first '('leet 'a 'f)) - это '(quote leet), а не ‘leet. Итак, вы сравниваете списки, а не символы.

'(...) уже цитирует содержимое списка. Если вы добавите дополнительные ' в списки, они сами будут указаны. А поскольку 'foo является сокращением для (quote foo), в кавычках он содержит список, содержащий эти символы.

Если вы просто напишите '(leet a f) без внутренних кавычек, все будет работать так, как вы ожидаете.

...