Common lisp Lisp:psetf未完全理解

Common lisp Lisp:psetf未完全理解,common-lisp,Common Lisp,我在SBCL中尝试此操作以翻转列表中的虚线对: (mapcar (lambda (x) (let ((num (random 2))) (if (= num 0) (psetf (cdr x) (car x) (car x) (cdr x)) x))) '((B . 21) (O . 24) (P

我在SBCL中尝试此操作以翻转列表中的虚线对:

(mapcar (lambda (x) (let ((num (random 2)))
                          (if (= num 0)
                             (psetf (cdr x) (car x) (car x) (cdr x))
                            x)))
                 '((B . 21) (O . 24) (P . 15) (R . 47) (K . 49)))
但是我得到了这个(ymmv):


这告诉我psetf不喜欢我正在做的事情。据我所知,
psetf
是破坏性的,返回
NIL
。我在这里不明白什么?

您观察到的行为是正确的,也是预期的: 返回
nil
并放置返回值 进入返回列表,因此当
num
为0时,您将得到
nil
, 当它为1时,得到原始单元格

易于修复:

(mapcar (lambda (x)
          (when (zerop (random 2))
            (psetf (cdr x) (car x) (car x) (cdr x)))
          x)
        '((B . 21) (O . 24) (P . 15) (R . 47) (K . 49)))
==> ((B . 21) (24 . O) (P . 15) (47 . R) (K . 49))
实际上,CL有一个宏 仅针对您的情况:

(mapcar (lambda (x)
          (when (zerop (random 2))
            (rotatef (cdr x) (car x)))
          x)
        '((B . 21) (O . 24) (P . 15) (R . 47) (K . 49)))
==> ((21 . B) (O . 24) (15 . P) (R . 47) (K . 49))
最后,请注意:

i、 例如,单元格相同,但列表不同

一致复制所有单元格可能会更好:

(defparameter *alist-2*
  (mapcar (lambda (x)
            (if (zerop (random 2))
                (cons (cdr x) (car x))
                (cons (car x) (cdr x))))
          *alist-0*))
*alist-0*
==> ((B . 21) (O . 24) (P . 15) (R . 47) (K . 49))
*alist-2*
==> ((21 . B) (O . 24) (15 . P) (R . 47) (K . 49))

通常,人们可能希望避免修改cons单元格<代码>缺点新的

CL-USER 76 > (mapcar (lambda (pair)
                       (if (= (random 2) 0)
                           (cons (cdr pair)
                                 (car pair))
                         pair))
                     '((B . 21) (O . 24) (P . 15) (R . 47) (K . 49)))
((21 . B) (24 . O) (P . 15) (47 . R) (49 . K))

请注意,结果中的某些cons单元格来自引用的数据。
(defparameter *alist-2*
  (mapcar (lambda (x)
            (if (zerop (random 2))
                (cons (cdr x) (car x))
                (cons (car x) (cdr x))))
          *alist-0*))
*alist-0*
==> ((B . 21) (O . 24) (P . 15) (R . 47) (K . 49))
*alist-2*
==> ((21 . B) (O . 24) (15 . P) (R . 47) (K . 49))
CL-USER 76 > (mapcar (lambda (pair)
                       (if (= (random 2) 0)
                           (cons (cdr pair)
                                 (car pair))
                         pair))
                     '((B . 21) (O . 24) (P . 15) (R . 47) (K . 49)))
((21 . B) (24 . O) (P . 15) (47 . R) (49 . K))