情商吗?在 Racket 中的行为与 eq 不同?在 Guile 中还是 Common Lisp 中的 eq?

Dem*_*ame 2 lisp comparison scheme racket

新年快乐!

我正在努力进入 Racket(我不是一个经验丰富的 Lisper)。

现在我在 Racket 8.3 中遇到了以下内容:

#lang racket
> (define str1 "hello")
> (define str2 "hello")
> (eq? str1 str2)
#t
Run Code Online (Sandbox Code Playgroud)

我期待#f像这里一样。在 Guile 和 Common Lisp 中,这被返回。

据此我可以重现以下行为符合预期:

> (set! str1 (string #\h #\e #\l #\l #\o))
> (set! str2 (string #\h #\e #\l #\l #\o))
> (eq? str1 str2)
#f
Run Code Online (Sandbox Code Playgroud)

但我不明白原因。

是不是,在 Racket 中,只有函数 STRING 返回两个不同的对象,而文字字符串却像符号一样是唯一的?因此,等式?行为通常,但文字字符串的处理方式有所不同?

你能好心给我解释一下吗?

非常感谢。

ign*_*ens 7

eq?作用与 Common Lisp 中的作用相同eq:它告诉您两个对象是否是同一个对象。

您所看到的是,通常无法定义相似的文字对象是否实际上是同一对象,并且使它们相同通常会带来好处。一个特别的好处是,这样可以使用更少的内存。

对于 Racket 来说,很明显,文字字符串是这样合并的,至少在某些情况下是这样。(但并非总是如此:给定以下程序

#lang racket

(define (ts)
  (define (getit prompt)
    (printf "~S? " prompt)
    (read))
  (eq? (getit "1")
       (getit "2")))

(ts)
Run Code Online (Sandbox Code Playgroud)

然后

$ racket ts.rkt
"1"? "foo"
"2"? "foo"
#f
Run Code Online (Sandbox Code Playgroud)

例如。)

一般来说,您不应该假设相似的文字实际上是否是同一个对象,因为系统可能会也可能不会选择合并它们,并且在任何特定情况下可能会也可能不会选择这样做。

举个例子,在 CL 中,如果您有一个包含此函数的文件

(defun foo ()
  (eq "foo" "foo"))
Run Code Online (Sandbox Code Playgroud)

当你编译该文件时,无论该函数返回 true 还是 false,它都是完全明确未定义的:即使为READ两个字符串返回不同的对象(我不确定是否需要这样做,但可能是),文件编译器是当然允许合并它们,因此只有一个文字字符串(当然,因此允许注意到该函数总是返回 true 并简单地将其转换为(defun foo () t))。

所以答案是:永远不要对相似的文字做出假设,无论是相同还是不同:如果您想要相似但不相同的对象,您需要使用定义为创建新对象的函数自己创建它们。