unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Stefan Schmiedl <s@xss.de>
To: Zelphir Kaltstahl <zelphirkaltstahl@posteo.de>, guile-user@gnu.org
Subject: Re: Surprising behavior of eq?
Date: Sun, 20 Sep 2020 15:57:43 +0200	[thread overview]
Message-ID: <687423933.20200920155743@xss.de> (raw)
In-Reply-To: <bae0d6aa-b0fb-e835-5a01-03fb34c46650@posteo.de>

Let's have a little shop talk with guile:

$ guile-3.0
GNU Guile 3.0.4-dirty
scheme@(guile-user)> (eqv? "a" "a")
$1 = #t

Hypothesis:
guile's reader recognizes that the contents of both string literals
are the same and feeds the same string to the calling function. 

Check:
If that were the case, the two strings should not only be eqv? but
also eq?

scheme@(guile-user)> (eq? "a" "a")
$2 = #t

To see a different behaviour we need to avoid these literals and replace
them by values not built while reading but while executing the code:

scheme@(guile-user)> (equal? (list->string (list #\a)) (list->string (list #\a)))
$3 = #t

Now we compare two different string values which happen to end up with
identical content. And, behold: They are neither eqv? nor eq?.

scheme@(guile-user)> (eqv? (list->string (list #\a)) (list->string (list #\a)))
$4 = #f
scheme@(guile-user)> (eq? (list->string (list #\a)) (list->string (list #\a)))
$5 = #f


Now let's see if that is consistent with the standard:

According to r5rs, section 6.1 "Equivalence predicates":

        The eqv? procedure returns #t if:
        ...
        * obj1 and obj2 are pairs, vectors, or strings that denote
          the same locations in the store (section 3.4).

So we have learned 
* that guile's reader reuses "store locations" for
  strings of identical content 
* that eqv? is not the right predicate for content based string comparison

HTH
s.

"Zelphir Kaltstahl" <zelphirkaltstahl@posteo.de>, 20.09.2020, 15:09:

> 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
>>


--
Stefan Schmiedl
EDV-Beratung Schmiedl, Berghangstr. 5, 93413 Cham
Büro: +49 (0) 9971 9966 989, Mobil: +49 (0) 160 9981 6278




  parent reply	other threads:[~2020-09-20 13:57 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-20 12:16 Surprising behavior of eq? Zelphir Kaltstahl
2020-09-20 12:19 ` Zelphir Kaltstahl
2020-09-20 12:58   ` Christopher Lemmer Webber
2020-09-20 13:09   ` Zelphir Kaltstahl
2020-09-20 13:52     ` John Cowan
2020-09-20 15:37       ` Zelphir Kaltstahl
2020-09-20 16:18         ` tomas
2020-09-20 17:05         ` John Cowan
2020-09-20 20:51           ` Linus Björnstam
2020-09-20 21:42             ` John Cowan
2020-09-20 13:57     ` Stefan Schmiedl [this message]
2020-09-20 15:42       ` Zelphir Kaltstahl
2020-09-20 17:26 ` Taylan Kammer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=687423933.20200920155743@xss.de \
    --to=s@xss.de \
    --cc=guile-user@gnu.org \
    --cc=zelphirkaltstahl@posteo.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).