由于dotimes是一个宏观的,看着它的宏扩展可以让事情更清晰:
你的第一个例子,展开:
(pprint (MACROEXPAND-1 '(dotimes (temp-one 10 temp-one))))
我得到以下的输出: (您可能因CL实施而异)
(BLOCK NIL
(LET ((#:G8255 10) (TEMP-ONE 0))
(DECLARE (CCL::UNSETTABLE TEMP-ONE))
(IF (CCL::INT>0-P #:G8255)
(TAGBODY
#:G8254 (LOCALLY (DECLARE (CCL::SETTABLE TEMP-ONE))
(SETQ TEMP-ONE (1+ TEMP-ONE)))
(UNLESS (EQL TEMP-ONE #:G8255) (GO #:G8254))))
TEMP-ONE))
有很多事情要做,但要看的关键是temp-one绑定到值0,并作为表达式的值(以标准lisp评估顺序)返回。
拿最后一个例子:
(pprint (macroexpand-1 '(dotimes (i n s) (incf s i))))
输出:
(BLOCK NIL
(LET ((#:G8253 N) (I 0))
(DECLARE (CCL::UNSETTABLE I))
(IF (CCL::INT>0-P #:G8253)
(TAGBODY
#:G8252 (INCF S I)
(LOCALLY (DECLARE (CCL::SETTABLE I))
(SETQ I (1+ I)))
(UNLESS (EQL I #:G8253) (GO #:G8252))))
S))
正如你可以在这里看到S的处理方式与温度,一个在之前的例子一样。
尝试以下一项,而没有经过最后一个变量:
(pprint (macroexpand-1 '(dotimes (i n) (do-something i))))
,你会得到:
(BLOCK NIL
(LET ((#:G8257 N) (I 0))
(DECLARE (CCL::UNSETTABLE I))
(IF (CCL::INT>0-P #:G8257)
(TAGBODY
#:G8256 (DO-SOMETHING I)
(LOCALLY (DECLARE (CCL::SETTABLE I))
(SETQ I (1+ I)))
(UNLESS (EQL I #:G8257) (GO #:G8256))))
NIL))
注意NIL是怎样的返回值。
结果窗体只是一个表单,它在循环完成后被评估为产生返回值(或多个)。它是可选的(如果你不出来,返回值将是'NIL')。在你的最后一个例子中,变量'S'用于累计在循环结尾返回的'N'下的所有整数的和。 – jkiiski