do v.do*:为什么相同的代码会产生不同的结果?

问题描述 投票:0回答:1

我正在摆弄

do macro
,我决定编写一个函数来反转列表:

(defun my-reverse (my-list)
  (do ((alist my-list (cdr alist))
       (acc nil (cons (car alist) acc)))
      ((null alist) acc)
    (format t "current: ~a~%" (car alist))))

--output:--
CL-USER> (my-reverse '(10 20 30))
current: 10
current: 20
current: 30
(30 20 10)

到目前为止一切都很好。但我发现将

do
更改为
do*
会产生不同的结果:

(defun my-reverse (my-list)
  (do* ((alist my-list (cdr alist))
        (acc nil (cons (car alist) acc)))
      ((null alist) acc)
    (format t "current: ~a~%" (car alist))))

--output:--    
(CL-USER> (my-reverse '(10 20 30))
current: 10
current: 20
current: 30
(NIL 30 20)

对此有何解释?

另外,因为

(car alist)
在代码中出现了两次,我想我应该尝试初始化一个变量并将其设置为等于
(car alist)
以简化代码:

(defun my-reverse (my-list)
  (do* ((alist my-list (cdr alist))
        (x (car alist))
        (acc nil (cons x acc)))
      ((null alist) acc)
    (format t "current: ~a~%" x)))

--output:--
CL-USER> (my-reverse '(10 20 30))
current: 10
current: 10
current: 10
(10 10 10)

好的,

x
需要一个步进器:

(defun my-reverse (my-list)
  (do* ((alist my-list (cdr alist))
        (x (car alist) (car alist))
        (acc nil (cons x acc)))
      ((null alist) acc)
    (format t "current: ~a~%" x)))

--output:--
CL-USER> (my-reverse '(10 20 30))
current: 10
current: 20
current: 30
(NIL 30 20)

那也没用。

接下来,我尝试在体内做积累:

(defun my-reverse (my-list)
  (do* ((alist my-list (cdr alist))
        (x (car alist) (car alist))
        (acc nil))
      ((null alist) acc)
    ((setf acc (cons x acc))
     (format "current: ~a~%")
     ))

但是,我收到了“非法函数调用”错误:

(setf acc (cons x acc))

主体是否允许更改循环变量?

lisp common-lisp sbcl
1个回答
0
投票

do
do*
之间的关系类似于
let
let*
之间的关系:并行分配与顺序分配。

引自超规格

对于

do
,在更新任何 var 之前都会评估所有步骤形式;为 vars 赋值是并行完成的,就像通过
psetq
一样。 因为所有步骤形式在任何变量更改之前都会被评估,所以评估时的步骤形式始终可以访问所有变量的旧值,即使其他步骤形式在它之前。

因此,在

(cons (car alist) acc)
中,
alist
的值是 前一个,而不是本次迭代设置的值。而
do*
,

对于

do*
,计算第一个步进形式,然后将值分配给第一个 var,然后计算第二个步进形式,然后将值分配给第二个 var,依此类推;为变量赋值是按顺序完成的,就像通过
setq

所以它看到了

alist
的当前版本,在第二次迭代中是
'(20 30)
,在最后一次迭代中是
nil
,而
(car nil)
nil

© www.soinside.com 2019 - 2024. All rights reserved.