unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: John Cowan <cowan@ccil.org>
To: Zelphir Kaltstahl <zelphirkaltstahl@posteo.de>
Cc: guile-user <guile-user@gnu.org>
Subject: Re: Surprising behavior of eq?
Date: Sun, 20 Sep 2020 09:52:06 -0400	[thread overview]
Message-ID: <CAD2gp_T3fjSX7F5yHRxLk60ypgzPepNPOv1SKQ+D4t_nx7L25A@mail.gmail.com> (raw)
In-Reply-To: <bae0d6aa-b0fb-e835-5a01-03fb34c46650@posteo.de>

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 <
zelphirkaltstahl@posteo.de> 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
>
>


  reply	other threads:[~2020-09-20 13:52 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 [this message]
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
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=CAD2gp_T3fjSX7F5yHRxLk60ypgzPepNPOv1SKQ+D4t_nx7L25A@mail.gmail.com \
    --to=cowan@ccil.org \
    --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).