3

I understand that (eq '(3 . d) '(3 . d)) returns nil, and (eq 3 3) returns t. But I do not understand why delq is deleting one (3 . d) in the second example each loop when y is (3 . d). Is mapc placing some type of invisible symbol on one of the (3 . d) but not the others such that only one (1) of them in the sequence is eq?

(let* ((original '(0 1 2 3 3 3 3 4 5 6))
       (copy (copy-list original)))
  (mapc (lambda (x)
          (mapc (lambda (y)
                  (message "y: %s | copy: %s" y copy)
                  (setq copy (delq y copy)))
                copy))
        original))

In the second example, one (3 . d) is deleted each loop when y is (3 . d).

(let* ((original '((0 . a) (1 . b) (2 . c) (3 . d) (3 . d)
                   (3 . d) (3 . d) (4 . e) (5 . f) (6 . g)))
       (copy (copy-list original)))
  (mapc (lambda (x)
          (mapc (lambda (y)
                  (message "y: %s | copy: %s" y copy)
                  (setq copy (delq y copy)))
                copy))
        original))

Note: copy-sequence is an alternative to copy-list a.k.a. cl-copy-list (defined in cl.el).

1
  • C-h S copy-sequence detailedly explains the "copy" behavior, though unlike copy-list, it doesn't work for dotted list.
    – xuchunyang
    Commented Jan 3, 2017 at 19:39

1 Answer 1

2

I think you basically explained what's going on when you explained the eq business: In the first loop, the first time you hit a 3, delq removes all the 3s, because they are eq to each other. In the second loop, each time you hit a (3 . d), the call to delq removes that particular (3 . d) and not the other (3 . d) because they are not eq to each other.

I guess you want to know how Emacs implements cons cells and eq to make different occurrences of (3 . d) not be eq to each other. Every time you evaluate a (3 . d), Emacs allocates some fresh, unused portion of memory for a cons cell and sets the car to 3 and the cdr to d, for cons cells eq tests whether or not they are stored in the same location in memory (if you are familiar with pointers, as they occur in C, for example, you'd say that for cons cells eq performs a pointer equality test). So there's no "extra symbol" required to make eq work that way.

(Strictly speaking to explain the results you also need to know that copy-list allocates new space for the list it returns, but reuses exactly the same contents as the input list.)

4
  • Would it be accurate for me state?: "The active element during each mapc loop will always be eq to the corresponding element of the SEQUENCE, even if the eq test would otherwise fail outside of a mapc context. The active element may be eq to more than one element if they would otherwise be eq."
    – lawlist
    Commented Jan 3, 2017 at 19:40
  • 3
    This has nothing to do with mapc. The expression (eq '(d . 3) '(d . 3)) may evaluate to true because the Lisp-reader may create only one copy for multiple equal cells. You can see this with something like (progn (setq x '(a . 0) y '(a . 0)) (setcar x 'b) y).
    – politza
    Commented Jan 3, 2017 at 21:09
  • See politza's comment answering yours, @lawlist (I think he or she forgot to ping you).
    – Omar
    Commented Jan 4, 2017 at 4:23
  • @politza In CL (eq '(d . 3) '(d . 3)) can return t. It is detailed in the CL specification that equal constant lists can be identified. Whether that is the case for Elisp is currently an open question. See emacs.stackexchange.com/q/45820/2370. For me it looks like that is unspecified for Elisp. Note that the evaluation of your example (progn (setq x '(a . 0) y '(a . 0)) (setcar x 'b) y) in an Org Elisp-source code block returns (a . 0).
    – Tobias
    Commented Nov 27, 2018 at 17:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.