首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是eq吗?球拍中的行为与eq不同?用诡计还是用普通的eq?

是eq吗?球拍中的行为与eq不同?用诡计还是用普通的eq?
EN

Stack Overflow用户
提问于 2022-01-02 11:01:15
回答 4查看 173关注 0票数 2

新年快乐!

我正在工作,我的球拍(不是一个解释李斯特)。

现在我在球拍8.3中遇到了以下情况:

代码语言:javascript
复制
#lang racket
> (define str1 "hello")
> (define str2 "hello")
> (eq? str1 str2)
#t

我以为#f喜欢这里。在Guile和Common中,这是返回的。

根据,我可以按照预期再现以下行为:

代码语言:javascript
复制
> (set! str1 (string #\h #\e #\l #\l #\o))
> (set! str2 (string #\h #\e #\l #\l #\o))
> (eq? str1 str2)
#f

但我不明白原因。

是吗,在球拍中只有函数字符串返回两个不同的对象,而文字字符串像符号一样是唯一的?因此,eq?通常情况下,文本字符串的处理方式不同吗?

你能对我解释一下吗?

非常感谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2022-01-02 13:24:25

eq?所做的与eq在公共Lisp中所做的事情是一样的:它告诉您两个对象是否是同一个对象。

您所看到的是,通常没有定义相似的文字对象是否实际上是相同的对象,而使它们相同往往会有好处。一个特别的好处是这样可以减少内存的使用。

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

代码语言:javascript
复制
#lang racket

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

(ts)

然后

代码语言:javascript
复制
$ racket ts.rkt
"1"? "foo"
"2"? "foo"
#f

例如)

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

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

代码语言:javascript
复制
(defun foo ()
  (eq "foo" "foo"))

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

因此,答案是:永远不要假设文本是相同的,或者是相同的,或者不是相同的:如果你想要相似但不完全相同的对象,你需要用一个函数来定义它们来创建新的对象。

票数 7
EN

Stack Overflow用户

发布于 2022-01-03 04:23:11

是吗,在球拍中只有函数字符串返回两个不同的对象.

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

代码语言:javascript
复制
(define a "a")
(eq? (string-append a a) (string-append a a)) ;=> #f

..。文字字符串就像符号一样独特吗?因此,eq?通常情况下,文本字符串的处理方式不同吗?

对于球拍,是的,这在文档中是有保证的

默认读取器(请参阅读字符串)生成的字符串常量是不可变的,它们在读-语法模式下被嵌入。

为了更详细地介绍一下,Racket使用read-syntax来读取您的程序,并在read-syntax中进行字符串读取。

代码语言:javascript
复制
(define a (syntax-e (read-syntax))) ; input "a"
(define b (syntax-e (read-syntax))) ; input "a"
(eq? a b) ;=> #t
票数 2
EN

Stack Overflow用户

发布于 2022-01-04 19:37:48

标准不想指定实现术语,而是列出了什么应该是#t,什么应该是#f,以及eq?始终都是eqv?,反之亦然。除了指针均匀度这一关键信息外,他们什么都写。即。当两个参数是相同的对象时,eq?返回#t,比如Java的==

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

在同一份报告中,试图更改文本被认为是一个错误。在string-set!中,如下所示:

代码语言:javascript
复制
(define (f) (make-string 3 #\*))
(string-set! (f) 0 #\?)  ‌⇒  unspecified

因此,make-string生成一个新的字符串,每个调用都不能使用,所以第一个示例是使用周期的OK Scheme代码。如果要将结果绑定到一个变量,然后执行它,您将可以访问如下所示的结果:

代码语言:javascript
复制
(define (f) (make-string 3 #\*))
(define test (f))
(string-set! test 0 #\?)  ‌⇒  unspecified
test  ‌                    ⇒  "?**"

现在,第二个示例将更多地讨论主题。

代码语言:javascript
复制
(define (g) "***")
(string-set! (g) 0 #\?)  ‌⇒  unspecified
             ; should raise  &assertion exception

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

对于那些调用(g)的人来说,大多数实现都不是这样的,当非法代码正常工作时,很可能会导致"?**""***"中的一个错误。

请回到您的代码:

代码语言:javascript
复制
(define str1 "hello")
(define str2 "hello")
(eq? str1 str2) ⇒  unspecified

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

代码语言:javascript
复制
(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,例如。通常是当他们看起来一样的时候。因此:

代码语言:javascript
复制
(equal? str1 str2)  ⇒  #t
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70555419

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档