的 检查 += 扩展找到错误 强>
+=
您需要检查扩展:
CL-USER 3 > (defmacro += (x y) (list 'setf x '(+ x y))) += CL-USER 4 > (macroexpand-1 '(+= a 1)) (SETF A (+ X Y)) T
上面的宏观扩展表明了这一点 x 和 y 使用,这是错误。 我们需要在宏函数中评估它们:
x
y
CL-USER 5 > (defmacro += (x y) (list 'setf x (list '+ x y))) += CL-USER 6 > (macroexpand-1 '(+= a 1)) (SETF A (+ A 1)) T
上面看起来更好。请注意顺便说一句。该宏已经存在于标准的Common Lisp中。它被称为 incf 。
incf
另请注意,您不需要它,因为您的副作用不需要 iterate 码。我们可以使用 + 函数没有设置任何变量。
iterate
+
的 样式 强>
您可能希望稍微调整一下Lisp样式:
GENSYM
&body
&rest
do
应用于您的代码,它现在看起来像这样:
(defmacro iterate (variable start end step &body body) "Iterates VARIABLE from START to END by STEP. For each step the BODY gets executed." (let ((end-variable (gensym "END")) (step-variable (gensym "STEP"))) `(do ((,variable ,start (+ ,variable ,step-variable)) (,end-variable ,end) (,step-variable ,step)) ((> ,variable ,end-variable) t) ,@body)))
在Lisp中,第一部分 - 变量,开始,结束,步骤 - 通常写在列表中。例如,参见 DOTIMES 。这使得例如可以制作 step 可选,并为其提供默认值:
DOTIMES
step
(defmacro iterate ((variable start end &optional (step 1)) &body body) "Iterates VARIABLE from START to END by STEP. For each step the BODY gets executed." (let ((end-variable (gensym "END")) (step-variable (gensym "STEP"))) `(do ((,variable ,start (+ ,variable ,step-variable)) (,end-variable ,end) (,step-variable ,step)) ((> ,variable ,end-variable) t) ,@body)))
让我们看看扩展,格式化以便于阅读。我们使用这个功能 macroexpand-1 ,它只进行一次宏扩展 - 而不是宏扩展生成的代码。
macroexpand-1
CL-USER 10 > (macroexpand-1 '(iterate (i 1 10 2) (print i) (print (* i 2)))) (DO ((I 1 (+ I #:STEP2864)) (#:END2863 10) (#:STEP2864 2)) ((> I #:END2863) T) (PRINT I) (PRINT (* I 2))) T
您可以看到由其创建的符号 gensym 也可以通过他们的名字来识别。
gensym
我们也可以使用函数让Lisp格式化生成的代码 pprint 给予正确的保证金。
pprint
CL-USER 18 > (let ((*print-right-margin* 40)) (pprint (macroexpand-1 '(iterate (i 1 10 2) (print i) (print (* i 2)))))) (DO ((I 1 (+ I #:STEP2905)) (#:END2904 10) (#:STEP2905 2)) ((> I #:END2904) T) (PRINT I) (PRINT (* I 2)))
我想到了。结果我在我的+ =宏和我的迭代宏中的其他几个地方出了问题。这是最终的工作结果。我忘记了 , 而我在写+ =宏。其他宏程序在哪里出现故障。
,
(defmacro += (x y) `(setf ,x (+ ,x ,y))) (defmacro iterate2 (control beginExpr endExpr incrExpr &rest bodyExpr) (let ((incr(gensym))(end(gensym)) ) `(do ((,incr ,incrExpr)(,end ,endExpr)(,control ,beginExpr(+= ,control ,incr))) ((> ,control ,end) T) ,@ bodyExpr ) ) )