lisp - Common Lisp 执行表达式作为宏中的参数
问题描述
因此,使用 common 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 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
当然是。
推荐阅读
- android - 我如何在行内居中小部件?
- powershell - 使用 Powershell 查看 SSRS 日志文件
- hybridauth - 从 2.xx 迁移到 3.xx 时,我应该如何处理 Hybrid_Endpoint::process()?
- docker - 如何在 docker volume ls --format 中打印嵌套字典成员值
- authentication - 单个用户使用 Nuxt Auth 登录多个 Nuxt.js 网站
- ssl - 无法在 Nginx 上禁用 TLSv1
- python - 通过 Windows 中的右键单击“打开方式”上下文菜单将文件传递给 Python,然后在另一个程序中打开
- c# - 使用输入参数的 CSHTML 页面调用 void 方法
- promise - JS 承诺:如何链接 `then` 调用?
- android - 在 Firebase 数据库中上传图像期间,将错误的 URL 提取到数据库中。需要一些指导。(Kotlin)