From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Zelphir Kaltstahl Newsgroups: gmane.lisp.guile.user Subject: Re: Surprising behavior of eq? Date: Sun, 20 Sep 2020 17:37:45 +0200 Message-ID: References: <8e1d9874-4659-cca5-03da-c2c0df102c56@posteo.de> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="35574"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 Cc: guile-user To: John Cowan Original-X-From: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Sun Sep 20 17:38:06 2020 Return-path: Envelope-to: guile-user@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kK1Ph-00099J-IC for guile-user@m.gmane-mx.org; Sun, 20 Sep 2020 17:38:05 +0200 Original-Received: from localhost ([::1]:38164 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kK1Pg-0005ke-J9 for guile-user@m.gmane-mx.org; Sun, 20 Sep 2020 11:38:04 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:55450) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kK1PV-0005k0-8N for guile-user@gnu.org; Sun, 20 Sep 2020 11:37:53 -0400 Original-Received: from mout01.posteo.de ([185.67.36.65]:57486) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kK1PR-0002Qd-JP for guile-user@gnu.org; Sun, 20 Sep 2020 11:37:53 -0400 Original-Received: from submission (posteo.de [89.146.220.130]) by mout01.posteo.de (Postfix) with ESMTPS id 344BD160061 for ; Sun, 20 Sep 2020 17:37:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.de; s=2017; t=1600616267; bh=BXd/EYeya+2yWg4k1heR1UAdNyale45leEXRM7w5LLY=; h=Subject:To:Cc:From:Date:From; b=QZLys9KbJlRpMbOD/QtR2bvGUN1IJrQRyg6dev64oX594WfXFbBiaFq1F4wPgcasw jGgcD7WTXEWHvfMT0HHoh/hdBhjYvMWDghKWWgh2anCc8l3rZOrFukNhx+i7o1ISwv Sc4ZKL7o9tz1xJu8q/RYcyEU5rD0UnnM0XhQfTWzZQM8lqYqm6wtE8yL2WWCUG4x7G PjcweXya643Jx4Pl2IiVQPK/F7uLVNwebQpjxT2L5aJmkMBIRRTECZo/bOz9zOBPF/ /R/APoW/QtZj1rSQIfX1+sQEBZL8crlKBgH3j7ZI3lH7rbwWQrOJlBiCSJtfWLcHsT LL0+YoZAKlU/g== Original-Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4BvWt241Z5z9rxB; Sun, 20 Sep 2020 17:37:46 +0200 (CEST) X-Tagtoolbar-Keys: D20200920173745878 In-Reply-To: Content-Language: en-US Received-SPF: pass client-ip=185.67.36.65; envelope-from=zelphirkaltstahl@posteo.de; helo=mout01.posteo.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/20 11:37:47 X-ACL-Warn: Detected OS = Linux 3.11 and newer [fuzzy] X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, NICE_REPLY_A=-0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Content-Filtered-By: Mailman/MimeDel 2.1.23 X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Original-Sender: "guile-user" Xref: news.gmane.io gmane.lisp.guile.user:16936 Archived-At: Hello John, hello Stefan! My previous understanding, it seems, was too shallow to explain the behavior I saw. I think I misread https://stackoverflow.com/a/17719745/1829329, where it says: "This is where the eqv? predicate comes into picture. The eqv? is exactly the same as the eq? predicate, except that it will always return #t for same primitive values." Of course SO is not a standard. Either it is simply wrong, or I misunderstood "primitive values" in that phrase. I thought: "Ah strings are a primitive value, so eqv? should work in all cases when comparing strings." However, this has been debunked. Anyway, your explanation makes sense to me and I learned something new: Schemes differ in the way they "consolidate" literals. I know Racket says it is not a Scheme any longer, but I still tried: ~~~~ Welcome to Racket v7.0. > (let ((g "xyz") (h "xyz")) (eqv? g h)) #t > (define g "xyz") > (define h "xyz") > (eqv? g h) #t > ~~~~ So it seems Racket consolidates literals from multiple top level expressions. While in GNU Guile: ~~~~ scheme@(guile-user)> (let ((g "xyz") (h "xyz")) (eqv? g h)) $1 = #t scheme@(guile-user)> (define g "xyz") scheme@(guile-user)> (define h "xyz") scheme@(guile-user)> (eqv? g h) $2 = #f scheme@(guile-user)> ~~~~ So there we have a difference in how literals are consolidated in GNU Guile and Racket. Interesting! Thank you for your explanation! The only thing I do not quite understand yet is: What is the difference between (eqv? ...) and (eq? ...) then? If (eqv? ...) is only #t if things get consolidated in the same store place, would that not be the same as pointer equivalence? Ah, OK, the difference is, that (eqv? ...) works for numbers, regardless of whether they are consolidated, while eq? does not recognize them as equivalent: ~~~~ (define a 3.0) (define b 3.0) (eq? a b) $6 = #f (eqv? a b) $7 = #t ~~~~ So even if they are not consolidated (put in the same store), (eqv? ...) has some internal logic to treat numbers differently, while (eq? ...) does not do that. In the Guile manual there is no example given, for which (eq? ...) and (eqv? ...) give different results: https://www.gnu.org/software/guile/manual/html_node/Equality.html. When I try the example given for (eq? ...), I get the same results for (eqv? ...): ~~~~ (define x (vector 1 2 3)) (define y (vector 1 2 3)) (eq? x x) ⇒ #t (eq? x y) ⇒ #f (eqv? x x) ⇒ #t (eqv? x y) ⇒ #f ~~~~ I also read Stefan's explanation, which seems to boil down to the same thing: Same or different locations in the "store". Also that (eqv? ...) is not the correct thing to use for strings. Best regards, Zelphir On 9/20/20 3:52 PM, John Cowan wrote: > What's happening is that you are trying to compare strings with an > inappropriate predicate.  Eqv? tests for *identity* (being the same > object), whereas equal? tests for *equality* (havng the same > structure).  Therefore, (equal? "foo" "foo") will always return #t, > and almost all the time that's the predicate you should use. > > The question then is: when are two strings identical and not merely > equal?  In the general case, they are identical if they are the result > of a single constructor.  Thus given: > > (define a (string #\a #\b #\c)) > (define b a) > > then (eqv? a b) => #t > > But given > > (define c (string #\a #\b #c)) > (define d (string #\a #\b #c)) > > then (eqv? c  d) => #f > > Finally, we have to deal with string literals.  If there is more than > one appearance of "xyz" in code, they are all equal, but are they > identical?  The answer is that it is implementation-dependent.  A > Scheme is free to consolidate all equal literals into the same > object.  It looks like Guile does so when they both appear in the same > top-level expression, but *not* in different top-level expressions.  > So given > > (define e "xyz") > (define f "xyz") > > then (eqv? e f) => #f > > But (let ((g "xyz") (h "xyz"))  (eqv? g h)) => #t, because Guile > consolidates the two equal literals into a single object.  If you try > this on Chibi Scheme, you'll get #f, because Chibi does *not* > consolidate string literals. > > I hope that is helpful. > > > > > On Sun, Sep 20, 2020 at 9:11 AM Zelphir Kaltstahl > > wrote: > > And I've noticed something more about equality stuff in the context of > tests: > > ~~~~ > (eqv? "a" "a") > $3 = #t > > ;; but > > (define char->string >   (λ (c) >     (list->string >      (list c)))) > > (import >   ;; unit tests >   (srfi srfi-64)) > > (test-begin "string-utils-test") > > (test-group >  "char-to-string-test" > >  (test-eqv "char->string converts a character to a string" >    "a" >    (char->string #\a))) > > (test-end "string-utils-test") > > %%%% Starting test string-utils-test  (Writing full log to > "string-utils-test.log") > $2 = ("string-utils-test") > :19: FAIL char->string converts a character to a string > # of unexpected failures  1 > ~~~~ > > So while (eqv? ...) gives the correct (?) result, the test procedure > (test-eqv ...) which seems to indicate using (eqv? ...) via its name > does not think of the two strings as equivalent. > > > On 20.09.20 14:19, Zelphir Kaltstahl wrote: > > Sorry, I misclicked "send" when I wanted to further edit my > e-mail ... > > > > My Guile version is: > > > > ~~~~ > > (version) > > $6 = "3.0.4" > > ~~~~ > > > > On 20.09.20 14:16, Zelphir Kaltstahl wrote: > >> Hello Guile users, > >> > >> I just noticed something weird about eq?. > >> > >> My Guile version is: > >> > >> > >> I get the different results, depending on whether I define some > >> bindings in a let or using define: > >> > >> (In Emacs Geiser:) > >> > >> ~~~~ > >> (define x '(10 9)) > >> (define y '(10 9)) > >> (eq? x y) > >> $2 = #f > >> > >> (let ([x '(10 9)] > >>       [y '(10 9)]) > >>      (eq? x y)) > >> $3 = #t > >> ~~~~ > >> > >> Is this intentional or a bug? > >> > >> I first noticed something strange when writing the following code: > >> > >> ~~~~DEFINITION~~~~ > >> (define make-multiple-list-remover > >>   (λ (equal-proc) > >>     (λ (lst unwanted) > >>       (let loop ([remaining-list lst]) > >>         (cond > >>          [(null? remaining-list) > >>           '()] > >>          [(equal-proc (car remaining-list) unwanted) > >>           (loop (cdr remaining-list))] > >>          [else > >>           (cons (car remaining-list) > >>                 (loop (cdr remaining-list)))]))))) > >> ~~~~ > >> > >> ~~~~TEST~~~~ > >> (let ([a '(9 10)] > >>       [b '(9 10)]) > >>   (test-equal "make-multiple-list-remover-03" > >>     `(1 2 (3) (4) ,a) > >>     ((make-multiple-list-remover eq?) > >>      `(a b (c) (d) ,a) b))) > >> ~~~~ > >> > >> I was wondering, why the test fails. I think (eq? ...) should > not be > >> able to see the equivalence of both lists a and b, just like when > >> defined using (define ...). > >> > >> I can also run it in the REPL and see the difference: > >> > >> ~~~~ > >> (define a '(9 10)) > >> (define b '(9 10)) > >> ((make-multiple-list-remover eq?) > >>  `(a b (c) (d) ,a) b) > >> $4 = (a b (c) (d) (9 10)) > >> > >> (let ([a '(9 10)] > >>       [b '(9 10)]) > >>   ((make-multiple-list-remover eq?) > >>    `(a b (c) (d) ,a) b)) > >> $5 = (a b (c) (d)) > >> ~~~~ > >> > >> Somehow the bindings of let seem to be different from the bindings > >> created using define. What about using define inside let? > >> > >> ~~~~ > >> > >> ~~~~ > >> -- > >> repositories: https://notabug.org/ZelphirKaltstahl > > Somehow the bindings of let seem to be different from the bindings > > created using define. What about using define inside let? > > > > ~~~~ > > (let ([unrelated 'bla]) > >   (define a '(9 10)) > >   (define b '(9 10)) > >   ((make-multiple-list-remover eq?) > >    `(a b (c) (d) ,a) b)) > > $7 = (a b (c) (d)) > > ~~~~ > > > > So there the define usage also differs from when I use define on > the top > > level. Perhaps that is the difference? On which level the > bindings are > > defined? > > > > Regards, > > Zelphir > > > -- > repositories: https://notabug.org/ZelphirKaltstahl >