Racket中的eq?与Guile中的eq或Common Lisp中的eq不同吗?



新年快乐!

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

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

#lang racket
> (define str1 "hello")
> (define str2 "hello")
> (eq? str1 str2)
#t

我以为 #f 像这里一样。在 Guile 和 Common Lisp 中,这被退回了。

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

> (set! str1 (string #h #e #l #l #o))
> (set! str2 (string #h #e #l #l #o))
> (eq? str1 str2)
#f

然而,我看不出原因。

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

你会这么好心地给我解释一下吗?

谢谢。

eq?所做的与eq在Common Lisp中所做的相同:它告诉你两个对象是否是同一个对象。

你所看到的是,通常没有定义相似的文字对象是否实际上是同一个对象,并且使它们相同通常会有好处。 一个特别的好处是,您可以通过这种方式使用更少的内存。

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

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

然后

$ racket ts.rkt
"1"? "foo"
"2"? "foo"
#f

例如。

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

例如,在CL中,如果您有一个包含此功能的文件

(defun foo ()
(eq "foo" "foo"))

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

所以答案是:永远不要假设文字相似或不相同:如果你想要相似但不相同的对象,你需要使用一个被定义为创建新对象的函数自己制作它们。

是不是,在 Racket 中只有函数 STRING 返回两个不同的对象......

不仅功能string。几乎每个字符串函数,如string-append,都可以创建两个不同的对象:

(define a "a")
(eq? (string-append a a) (string-append a a)) ;=> #f

。文字字符串像符号一样是唯一的?因此,情商?行为正常,但文字字符串的处理方式不同?

对于球拍,是的,这在文档中得到了保证:

默认读取器生成的字符串常量(请参阅读取字符串)是不可变的,它们以读取语法模式暂留。

为了详细说明,Racket使用read-syntax来读取您的程序,而read-syntax中的字符串读取是暂存的。

(define a (syntax-e (read-syntax))) ; input "a"
(define b (syntax-e (read-syntax))) ; input "a"
(eq? a b) ;=> #t

该标准不想规定实现术语,而是列出了应该#t的内容,应该#f的内容以及eq?的所有内容也总是eqv?,反之亦然。他们写了除指针相等性的关键信息之外的所有内容。即。 当两个参数是同一个对象时,eq?返回 #t,就像 Java 的==一样。

在方案中,未指定(eq? "a" "a")#t#f都是可接受的结果。这是报告中的例子之一。"a"'(a b c)等文本值是不可变的。这是从引用到有关存储模型的信息的引用。

在同一报告中,尝试改变文字被认为是一个错误。对于如下所示string-set!,如下所示:

(define (f) (make-string 3 #*))
(string-set! (f) 0 #?)  ‌⇒  unspecified

因此,make-string每次调用都会创建一个新字符串,您真的无法使用,因此第一个示例是浪费周期的OK方案代码。如果要将结果绑定到变量,然后执行此操作,则可以访问如下所示的结果:

(define (f) (make-string 3 #*))
(define test (f))
(string-set! test 0 #?)  ‌⇒  unspecified
test  ‌                    ⇒  "?**"

现在第二个例子更贴主题。

(define (g) "***")
(string-set! (g) 0 #?)  ‌⇒  unspecified
; should raise  &assertion exception

R5RS甚至说它甚至不是Scheme,所以任何结果都可以,而R6RS和后来强烈建议尝试变异应该引发异常。

对于那些调用(g)的人来说,大多数实现并非如此,当非法代码正常工作时,最有可能导致"?**""***"之一。

做回你的代码:

(define str1 "hello")
(define str2 "hello")
(eq? str1 str2) ⇒  unspecified

出于完全相同的原因,未指定(eq? "a" "a")。解释器可能总是返回#f甚至编译的代码,但编译后的代码更有可能返回#t

(define str1 (string #h #e #l #l #o))
(define str2 (string #h #e #l #l #o))
(eq? str1 str2)  ⇒  #f

它们总是不同的,因为(string #h #e #l #l #o)创建一个新字符串,并且由于str1str2是分开创建的,它们是看起来相同的不同字符串。

知道,可以检查此类复合数据类型是否与equal?相等,当两个对象被视为相同时,通常当它们看起来相同时,这些数据类型将返回#t。因此:

(equal? str1 str2)  ⇒  #t

我想,你可能对这篇论文感兴趣,Equal Rights for Functional Objects or, The More Things Change, The More They Are the Same以获得完整的(哲学)答案。

相关内容

  • 没有找到相关文章

最新更新