【问题标题】:Lisp macro that does loop "unrolling"循环“展开”的 Lisp 宏
【发布时间】:2011-11-05 17:43:57
【问题描述】:

我使用 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 '(unroll))” 显示 NIL。

我做错了什么?

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

非常感谢您的帮助(我是 LISP 新手)。

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

【问题讨论】:

    标签: macros lisp


    【解决方案1】:

    你应该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))))))))
    

    【讨论】:

      猜你喜欢
      • 2018-11-11
      • 2015-03-29
      • 2016-01-30
      • 1970-01-01
      • 2016-08-07
      • 2012-04-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多