unofficial mirror of bug-guile@gnu.org 
 help / color / mirror / Atom feed
From: Taylan Kammer <taylan.kammer@gmail.com>
To: Maxime Devos <maximedevos@telenet.be>, 48318@debbugs.gnu.org
Subject: bug#48318: (ice-9 match) does not allow distinguishing between () and #nil
Date: Thu, 13 May 2021 23:21:48 +0200	[thread overview]
Message-ID: <6c3a61c2-0449-9f7c-a978-b034803bcebd@gmail.com> (raw)
In-Reply-To: <26e0536a8f0c16f53002b045cb7e9a30a1e8a09e.camel@telenet.be>

On 13.05.2021 22:39, Maxime Devos wrote:
> Taylan Kammer schreef op do 13-05-2021 om 21:14 [+0200]:
>> Hi Maxime,
>>
>> I believe that match conflating () and #nil is the right thing,
>> even if the current implementation does it unintentionally.
>>
>> Those two values should be considered "the same" in most situations
>> even though (eqv? #nil '()) is false.
> 
> Conflating #nil and () is reasonable for my use case,
> though this conflation should be documented.

Agree, it should definitely be documented.

>> In fact I think they should be equal? to each other.  It feels
>> wrong that (equal? '(foo . #nil) '(foo . ())) evaluates to false,
>> even though both arguments represent the list '(foo).
> 
> The guile manual has some information on this.
> (6.24.2.1 Nil, under 6.24.2 Emacs Lisp).

Good catch.  I see it mentions that equal? is expected to be
transitive, so if (equal? #nil '()) and (equal? #nil #f) were
both true, (equal? '() #f) would have to be too, which would
be wrong for a Scheme implementation.

We could however make it equal? to just one of the two without
making equal? non-transitive.  And if we're going to do that,
I think the empty list would be the better choice, because of
the role it plays in the structure of lists.  Without any data
to verify this, I'd say that situations where #nil surprises
programmers by not being equal? to '() are likely to come up
much more often than cases where it surprises programmers by
not being equal? to #f.

The parallel between equal?-ness and external representation
also comes to mind.  I think it's not a concrete rule, but
there's the general expectation that two objects are equal?
if their external representation is the same, which is the
case for (foo . #nil) and (foo . ()), which would both be
canonically represented as (foo).

We could also go in the other direction and make Scheme's
write procedure output (foo . #nil) as (foo . #nil), but I
think that would be less desirable.

>> Please note that #nil is not ever supposed to be used intentionally.
> I know, but ...
>> It's there purely as an Elisp compatibility trick, and the only time
>> Scheme could should receive it is when receiving data generated by
>> Elisp code.  For instance when Elisp code generates a list, it would
>> be terminated by #nil.  (Which is why I think it should equal? '().)
> 
> I have been porting some common lisp code to Guile Scheme. I replaced
> '() with #nil, which allows me to largely ignore whether Lisp nil is used
> as end-of-list or as boolean for now (I'm in the process of replacing it
> with '() or #f where appropriate).

Exciting!  I guess that's one feasible extra use-case for #nil,
but as you noted it yourself, it's probably best to rewrite the
code to eliminate all the assumptions that the end-of-list object
is false as a Boolean.

> Being able to directly refer to #nil, to perform equality checks like
> (eq? #f #nil) --> #f, (eq? '() #nil) --> #f, ... can be useful for writing
> Scheme code that could be called from both elisp and Scheme when the
> compatibility isn't transparent.  For example, suppose (ice-9 match) actually
> did not conflate #nil and () (which is what I initially thought; I expected
> (ice-9 match) to compare atoms with eqv?), then the
> following code ...
> 
> ;; Somewhat contrived (untested), but based on some real code
> (define 
>   (match-lambda
>     ((_ . stuff) stuff)
>     (() 0)))
> 
> ... would need to be rewritten to something like ...
> 
> ;; Somewhat contrived (untested), but based on some real code
> (define 
>   (match-lambda
>     ((_ . stuff) stuff)
>     (() 0)
>     (#nil 0)))

Indeed.

> Also, consider the 'case' syntax.

Case is defined in terms of eqv? in the standards so I guess
it should differentiate between #nil and ().  Unlike match,
which does pattern matching on lists.

> Greetings,
> Maxime.
> 

- Taylan





      reply	other threads:[~2021-05-13 21:21 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-09 16:42 bug#48318: (ice-9 match) does not allow distinguishing between () and #nil Maxime Devos
2021-05-13 19:14 ` Taylan Kammer
2021-05-13 20:39   ` Maxime Devos
2021-05-13 21:21     ` Taylan Kammer [this message]

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=6c3a61c2-0449-9f7c-a978-b034803bcebd@gmail.com \
    --to=taylan.kammer@gmail.com \
    --cc=48318@debbugs.gnu.org \
    --cc=maximedevos@telenet.be \
    /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).