解释Lisp的dotimes:结果形式是做什么的?

时间:2017-07-29 02:14:37

标签: common-lisp

我正在查看dotimes上的LispWorks Hyperspec,但我不明白第三个变量[result-form]正在做什么。示例如下:

(dotimes (temp-one 10 temp-one)) =>  10
(setq temp-two 0) =>  0
(dotimes (temp-one 10 t) (incf temp-two)) =>  T
temp-two =>  10

Hyperspec说

  

...然后评估结果形式。当时结果形式是   处理后,var与执行正文的次数绑定。

不确定这是什么意思。为什么这两个dotimes示例中需要第三个变量?我似乎完全可以在第二个例子中完全放弃它,它可以工作。我的下一个例子(不知道我在哪里找到它),

(defun thing (n)
    (let ((s 0))
      (dotimes (i n s)
        (incf s i))))

也困惑我。 s服务的用途是什么?

1 个答案:

答案 0 :(得分:4)

由于 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与前面例子中的temp-one相同。

在不传递最后一个变量的情况下尝试一个:

(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是如何返回值。