3
我與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」之一。它發出「訪問指令」從board [y] [x]讀取,因此它只能用於存在「board」的地方,如上面的函數「foo」。
這工作 - 然後我意識到...我可以走得更遠。這兩個嵌套循環是「靜態」約束:對於y,從0到height-1,對於x從3到(width-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「(披))」 顯示我NIL。
我在做什麼錯?
如果不清楚,我想使用兩個嵌套循環,並在外循環的開始和內循環的每次迭代發出「代碼」。
任何幫助最讚賞(我是LISP新手)。
UPDATE:後@larsmans'之類的建議,我成功地將這種變化我的代碼 - 和我極爲滿意,我看到的Lisp的版本我Score4 algorithm成爲第2個最快的實現,僅次於C和C++ (並且比OCaml快!)。
好極了!非常感謝你,我敬畏LISP宏的力量...... – ttsiodras