Как эквалайзер? в ракетке работают с символами и цифрами? - PullRequest
3 голосов
/ 03 февраля 2020

В документе Racket сказано, что «eq? return #t, если v1 и v2 относятся к одному и тому же объекту», но два fixnums, которые =, также совпадают в соответствии с eq?, = «возвращает #t, если все аргументы численно равны». Я не могу найти сообщения о «числах» и «символах», но в найденном примере:

> (eq? 'yes 'yes)
#t

Это противоречит вышесказанному, поскольку выше никогда не упоминалось, что symbol было специальные, поэтому 'yes и 'yes не одинаковы.

Этот еще больше запутывает меня:

> (eq? (expt 2 100) (expt 2 100))
#f
> (eq? (* 6 7) 42)
#t

, если числа проверяются численно, тогда (eq? (expt 2 100) (expt 2 100)) должно вернуться #t, в противном случае числа проверяются по ссылке, тогда (eq? (* 6 7) 42) должно возвращать #f, так что я думаю, что обе вышеупомянутые ситуации не верны ...

Почему?!

Ответы [ 2 ]

5 голосов
/ 03 февраля 2020
(expt 2 100)

слишком велик, чтобы быть fixnum. Давайте попробуем оценить:

(expt 2 100)  ; => 1267650600228229401496703205376
(fixnum? (expt 2 100)) ; => #f
(expt 2 10) ; => 1024
(fixnum? (expt 2 100)) ; => #t

Это связано с тем, что большие числа выделяются в нескольких ячейках памяти (представьте их как список групп цифр).

С другой стороны, каждый Символ при прочтении «усваивается». Это означает, что при первом чтении для него создается новое значение символа. Впоследствии, когда он снова читается, система проверяет, присутствует ли уже символ с таким именем, и в этом случае возвращается старое значение символа, не создавая никакого нового объекта в памяти. Итак:

(eq 'yes 'yes) ; => #t

, поскольку два разных символа с одинаковыми именами фактически являются одним и тем же объектом в памяти.

4 голосов
/ 03 февраля 2020

Это дает дополнительную информацию в дополнение к ответу @ Рензо

как я могу проверить, является ли тип данных «внутренним»

Ответ таков: сложный.

Одним из факторов является читатель :

Символы, ключевые слова, строки, байтовые строки, регулярные выражения, символы и числа, созданные читателем в * Режим 1014 * - это interned , что означает, что такие значения в результате read-syntax всегда равны eq?, когда они равны equal? (либо от одного и того же вызова, либо от других вызовов read-syntax). Символы и ключевые слова интернированы в режимах read и read-syntax. Отправка интернированного значения через местный канал не обязательно приводит к интернированному значению в принимающем месте. См. Также datum-intern-literal и datum->syntax.

Так что (eq? (expt 2 100) (expt 2 100)) возвращает #f, поскольку (expt 2 100) необходимо вычислять во время выполнения. С другой стороны, (eq? 1267650600228229401496703205376 1267650600228229401496703205376) возвращает #t, поскольку значение становится очевидным во время чтения, что позволяет Racket интернировать число.

Другим фактором являются типы данных. Например, фикснум всегда интернируется, даже если значение не видно во время чтения, согласно https://docs.racket-lang.org/reference/numbers.html

Два фикснума, которые =, также одинаковы согласно eq?. В противном случае результат применения eq? к двум числам не определен

Это означает, что (eq? (+ 1 2) 3) гарантированно будет #t.

Символ обычно интернирован, но он возможно сделать это без поддержки через string->uninterned-symbol и gensym.

Символ похож на неизменяемую строку, но символы обычно интернированы, так что два символа с одинаковыми символьное содержимое обычно равно eq?.

Две процедуры string-> uninterned-symbol и gensym генерируют неустранимые символы, т. е. символы, которые не являются eq ?, eqv? или равны? на любой другой символ, хотя они могут печатать так же, как и другие символы.

Итак:

> (eq? (string->symbol "ab") (string->symbol (string-append "a" "b")))
#t
> (eq? (string->uninterned-symbol "ab") (string->uninterned-symbol "ab"))
#f
...