从您的最新版本开始,与旧版本不同,这至少是宏的合理候选者:
(defmacro foo (someExpression count-var)
`(do ((,count-var 0 (+ ,count 1)))
((= ,count-var 5) T)
`(eval (,someExpression))))
那么什么是扩展(foo (print 1) c)
?
(foo (print 1) x)
-> (do ((x 0 (+ x 1))) ((= x 5) t)
`(eval (,someexpression)))
好吧,那是一场灾难:嵌套的反引号在做什么?让我们删除它:
(defmacro foo (someExpression count-var)
`(do ((,count-var 0 (+ ,count 1)))
((= ,count-var 5) T)
(eval (,someExpression))))
(foo (print 1) x)
-> (do ((x 0 (+ x 1))) ((= x 5) t)
(eval ((print 1))))
这不那么灾难性,但eval
形式完全是虚假的。我们可以通过将其更改为至少在语法上合法来使其“工作”:
(defmacro foo (someExpression count)
`(do ((,count 0 (+ ,count 1)))
((= ,count 5) T)
(eval ,someExpression)))
现在
(foo (print 1) x)
-> (do ((x 0 (+ x 1))) ((= x 5) t)
(eval (print 1)))
这将“起作用”,但纯粹是巧合:因为(print 1)
返回1
和值1
is 1
。
(foo (print 'foo) x)
-> (do ((x 0 (+ x 1))) ((= x 5) t)
(eval (print 'foo)))
这是一个运行时错误。
但是......你为什么要使用eval
? eval
对于您能想到的几乎所有问题,它都是一个糟糕的、糟糕的解决方案,除非该问题的解决方案被称为“代码注入攻击”,在这种情况下,它不仅糟糕,而且是错误的。所以我们只是删除它。
(defmacro foo (someExpression count)
`(do ((,count 0 (+ ,count 1)))
((= ,count 5) T)
,someExpression))
现在
(foo (print 'foo) x)
-> (do ((x 0 (+ x 1))) ((= x 5) t)
(print 'foo))
这看起来像我们想要的代码转换。所以,最后:
> (foo (print 'foo) x)
foo
foo
foo
foo
foo
t
最后,这很好。这有效:
> (foo (print x) x)
0
1
2
3
4
t
与对问题的另一个编辑一样,将变量名放在第一位并允许使用一堆表达式可能更有用:
(defmacro foo (count-var &body forms)
`(do ((,count-var 0 (+ ,count-var 1)))
((= ,count-var 5))
,@forms))
这现在将允许在正文中使用多个表达式。我们可以更进一步:我们可以允许它指定迭代次数和返回值`:
(defmacro foo ((count-var &optional (count 1) (value 'nil)) &body forms)
`(do ((,count-var 0 (1+ ,count-var)))
((= ,count-var ,count) ,value)
,@forms))
现在
> (foo (x 2)
(print x)
(print (* x 2)))
0
0
1
2
nil
嗯,这个宏的名字dotimes
当然是。