关于Lexical scope的一个问题

;; -*- lexical-binding: t; -*-
(let ((lst))
  (defun my-remove (item)
    (delete item lst))
  (defun my-add (item)
    (add-to-list 'lst item))
  (defun my-show ()
    (message "%s" lst)))

然后

(my-add 1)
(my-remove 1)
(my-show)

讲道理应该结果是nil,但实际上是'(1),那么问题来了,delete为啥不遵守lexical scope呢?


(delete ELT SEQ)

Delete members of SEQ which are ‘equal’ to ELT, and return the result.
SEQ must be a sequence (i.e. a list, a vector, or a string).
The return value is a sequence of the same type.

If SEQ is a list, this behaves like ‘delq’, except that it compares
with ‘equal’ instead of ‘eq’.  In particular, it may remove elements
by altering the list structure.

If SEQ is not a list, deletion is never performed destructively;
instead this function creates and returns a new vector or string.

****** Write ‘(setq foo (delete element foo))’ to be sure of correctly
changing the value of a sequence ‘foo’. ******

delete 简单的理解是返回一个新的对象,不会去修改旧的

delete 有时会修改参数,有时不会:

(mapcar (lambda (n)
          (let ((l (list 1 2 3)))
            (delete n l)
            l))
        '(1 2 3))
;; =>  ((1 2 3) (1 3) (1 2))

当你仅删除第一个元素时,delete 不会修改列表,因为没必要,这种情况下直接返回 cdr 即可

(delete x l) = (cdr l) ;; 当 x 是 l 的第一个元素时

唯一真正可靠的是其返回值,所以 delete 几乎总是用 (setq l (delete x l))

2 个赞