我使用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更快!)。
答案 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))))))))