执行循环“展开”的Lisp宏

时间:2011-11-05 17:43:58

标签: macros lisp

我使用Lisp宏的第一步......

(defconstant width 7)
(defconstant height 6)
...
; board is a 2D array of width x height
; and this is my first ever macro:
(defmacro at (y x)
  `(aref board ,y ,x))
; "board" must be available wherever the macro is used.

(defun foo (board ...)
  ...
  (loop for y from 0 to (1- height) do
    ; thanks to the "at" macro, this is cleaner:
    (let ((score (+ (at y 0) (at y 1) (at y 2))))
      (loop for x from 3 to (1- width) do
        (incf score (at y x))
        ; ...do something with score
        (decf score (at y (- x 3)))))))

代码使用我的第一个宏,即“at”宏。它发出“访问指令”以从板[y] [x]读取,因此它只能用于存在“board”的地方,如上面的函数“foo”。

这很有效 - 然后我意识到......我可以走得更远。

两个嵌套循环是“静态”约束的:y为0到高度-1,x为3到(宽度-1)......所以从理论上讲,我可以创建一个发出的宏(展开!)在循环代码中完成的确切的incf和decf指令!

我试过了:

(defmacro unroll ()
  (loop for y from 0 to (1- height) do
    `(setf score (+ (at ,y 0)  (at ,y 1) (at ,y 2)))
    (loop for x from 3 to (1- width) do
     `(incf score (at ,y ,x))
     `(decf score (at ,y (- ,x 3))))))

...但失败了 - “(macroexpand-1'(展开))”显示我没有。

我做错了什么?

如果不清楚,我想使用两个嵌套循环,并在外部循环的开头发出“代码”,并在内部循环的每次迭代中发出。

任何最感谢的帮助(我是LISP新手)。

更新:在@larsmans的善意建议之后,我成功地将此更改应用于我的代码 - 并且令我非常满意,我看到我的Score4 algorithm的Lisp版本成为第二个最快的实现,仅支持C和C ++(并且比OCaml更快!)。

1 个答案:

答案 0 :(得分:3)

你应该collect在宏loop内生成的陈述,而不是假装用do执行它们:

(defmacro unroll ()
  (loop for y from 0 to (1- height)
        collect
          `(begin (setf score (+ (at ,y 0)  (at ,y 1) (at ,y 2)))
                  ,@(loop for x from 3 to (1- width)
                          collect `(begin (incf score (at ,y ,x))
                                          (decf score (at ,y (- ,x 3))))))))