常见的Lisp dotimes结果之谜

时间:2018-11-21 05:28:01

标签: loops common-lisp

我明白了

(dotimes (temp-one 10 temp-one))

来自dotimes上的Hyperspec示例。运行此命令将得出答案10。因此,位于第三个参数位置的temp-one充当返回的“结果”,但是当dotimes从0开始并仅变为9时,它如何达到10。 ?

>(dotimes (temp-one 10 temp-one) (format t "~3d " temp-one))
  0   1   2   3   4   5   6   7   8   9 
10

我在这里缺少第三个参数吗?

2 个答案:

答案 0 :(得分:5)

如果您查看dotimes Hyperspec entry,则说明它是一个,这意味着您可以通过调用 macroexpand 来看到“内幕”:

(macroexpand '(dotimes (i 10 i)))

SBCL:

(BLOCK NIL
  (LET ((I 0))
    (DECLARE (TYPE UNSIGNED-BYTE I))
    (TAGBODY
      (GO #:G386)
     #:G385
      (TAGBODY)
      (PSETQ I (1+ I))
     #:G386
      (UNLESS (>= I 10) (GO #:G385))
      (RETURN-FROM NIL (PROGN I)))))

Allegro CL:

(do ((i 0 (1+ i)))
    ((>= i 10) i))

在两种情况下,迭代变量 i 均增加1,然后完成最终测试(>= i 10)。正如jkiiski写道:

  

“在处理结果形式时, var 绑定到执行主体的次数。”

在变量增加并测试之后,对

以及(return-from ..)形式(SBCL)和i形式(Allegro CL)进行评估。

答案 1 :(得分:4)

Hyperspec说:

  

在处理result-form时,var绑定到   尸体被处死的次数。

因此,在第三种形式(即结果形式)中,变量首先绑定到主体被执行的次数,然后对第三种形式进行求值。

这就是为什么变量值是10而不是当前值9的原因。

这也是可见的

(macroexpand-1 '(dotimes (temp-one 3 temp-one) (format t "~3d~%" temp-one)))

;; resulting in CLISP in:
;; (DO ((TEMP-ONE 0 (1+ TEMP-ONE))) ((>= TEMP-ONE 10) TEMP-ONE)
;;  (FORMAT T "~3d~%" TEMP-ONE)) ;
;; T

最后,(1+ TEMP-ONE)DO循环返回,DOTIMES扩展到--如@zut所指出。