Subject: bug#48318: (ice-9 match) does not allow distinguishing between () and #nil

From: Maxime Devos <[email-masked]>
Date: Thu, 13 May 2021 22:39:45 +0200

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.

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

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

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

Also, consider the 'case' syntax.

Greetings,
Maxime.