Order of content: 1] --- Setup information 2] --- what is the procedure nil? 3] --- snippet of code that trigger the bug 4] --- snippet of code that doesn't trigger the bug 5] --- Summary and end
1] --- Setup : $ ./config.guess x86_64-pc-linux-gnu $ guile --version guile: warning: failed to install locale guile (GNU Guile) 2.2.3 etc ... -> Guile was installed in a foreign Gnu/Linux distribution via Guix. 2] --- The procedure nil? is not listed in the procedure index : https://www.gnu.org/software/guile/docs/docs-2.0/guile-ref/Procedure-Index.html There is a page that speak about nil : https://www.gnu.org/software/guile/manual/html_node/Nil.html However it doesn’t mention the nil? Procedure The only documentation that I found about nil? is this one : (procedure-documentation nil?) => "- Scheme Procedure: nil? x\n Return `#t' iff X is nil, else return `#f'." (procedure-documentation null?) => "- Scheme Procedure: null? x\n Return `#t' iff X is the empty list, else `#f'." The procedure documentation is not the same for nil? and null? They seem nonetheless to be the same. (null? #nil) => #t (null? ‘()) => #t (nil? #nil) => #t (nil? '()) => #t 3] --- Here is the bug that I found : ;;; -START- code with the bug -START- ;;; (define (strange lst) (let loop ((lst lst) (is-empty '())) (cond ((nil? lst) (if (nil? is-empty) 'works (list 'should-not-occur is-empty))) (else (loop (cdr lst) is-empty))))) (strange '()) => (should-not-occur ()) (strange #nil) => (should-not-occur ()) ;;; -END- code with the bug -END- ;;; 4] --- And here follows 3 version that doesn’t trigger this bug. ;;; in this one we remove the call to the loop in the else clause ;;; -START- code that works (1) -START- ;;; (define (not-strange-1 lst) (let loop ((lst lst) (is-empty '())) (cond ((nil? lst) (if (nil? is-empty) 'works (list 'should-not-occur is-empty))) (else 'no-more-bug)))) (not-strange-1 '()) => works (not-strange-1 #nil) => works ;;; -END- code that works (1) -END- ;;; ;;; we change the ‘() of is-empty to #nil ;;; -START- code that works (2) -START- ;;; (define (not-strange-2 lst) (let loop ((lst lst) (is-empty #nil)) (cond ((nil? lst) (if (nil? is-empty) 'works (list 'should-not-occur is-empty))) (else (loop (cdr lst) is-empty))))) (not-strange-2 '()) => works (not-strange-2 #nil) => works ;;; -END- code that works (2) -END- ;;; ;;; if we use null? instead of nil? at the critical point (nil? is-empty) ;;; -START- code that works (3) -START- ;;; (define (not-strange-3 lst) (let loop ((lst lst) (is-empty '())) (cond ((nil? lst) (if (null? is-empty) 'works (list 'should-not-occur is-empty))) (else (loop (cdr lst) is-empty))))) (not-strange-3 '()) => works (not-strange-3 #nil) => works ;;; -END- code that works (3) -END- ;;; 5] --- So in summary : 1) removing the call to the loop in the else clause remove the bug. This is interesting because we don’t enter the else clause 2) using the #nil instead of ‘() did change the outcome. But except for this case, it doesn't seem to change the outcome to use #nil or ‘() 3) using null? Instead of nil? did change the outcome. This is similar to point 2. except that we change the procedure instead of the value. I think that there is 2 way to look at this bug: The first one is to consider that it is a bug because nil? and null? should give the same answer. The second one is to consider that nil? should only answer #t when we use it with #nil, and otherwise give #f (this include ‘() ). --- If you require any further information or did not understand what I said, feel free to contact me at calc...@disroot.org