guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Surprising behavior of eq?


From: Stefan Schmiedl
Subject: Re: Surprising behavior of eq?
Date: Sun, 20 Sep 2020 15:57:43 +0200

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]