如何解决Common Lisp 执行表达式作为宏中的参数
所以使用普通的 lisp,我希望能够做这样的事情:
(defmacro foo (count &rest someExpression)
`(do
((,count 0 (+,count 1)))
((=,count 5) T)
`(eval,someExpression)
)
)
(foo (print 1) temp)
结果是它打印了 1 5 次。我不想简单地直接调用 (print 1),而是通过宏参数传递表达式并通过宏调用它。换句话说,宏 foo 应该将任何表达式作为输入处理并运行它。这种情况似乎不起作用。
编辑以阐明明确的脚本和预期功能。
解决方法
从你最近的版本开始,它至少是一个与旧版本不同的宏的合理候选:
(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 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 5) T)
(eval,someExpression)))
现在
(foo (print 1) x)
-> (do ((x 0 (+ x 1))) ((= x 5) t)
(eval (print 1)))
这将“有效”,但纯粹是巧合:因为 (print 1)
返回 1
而 1
的值为 1
。
(foo (print 'foo) x)
-> (do ((x 0 (+ x 1))) ((= x 5) t)
(eval (print 'foo)))
这是一个运行时错误。
但是......你为什么使用eval
? eval
对几乎所有你能想到的问题来说都是一个糟糕的、糟糕的解决方案,除非该问题的解决方案被称为“代码注入攻击”,在这种情况下,它不仅糟糕:它是错误的。所以我们只需将其删除。
(defmacro foo (someExpression count)
`(do ((,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 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
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。