Common Lisp 执行表达式作为宏中的参数

Common Lisp Execute expression as parameter in macro

所以使用普通的 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 表格完全是伪造的。我们可以通过将其更改为至少在语法上合法来使 'work':

(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)))

这会 'work' 但这纯粹是巧合:因为 (print 1) returns 11 的值是 1.

(foo (print 'foo) x)
  -> (do ((x 0 (+ x 1))) ((= x 5) t)
       (eval (print 'foo)))

这是一个 运行 时间错误。

但是...您为什么要使用 evaleval 对几乎所有你能想到的问题来说都是一个糟糕透顶的解决方案,除非问题的解决方案被称为 'code injection attack',在这种情况下,它不仅糟糕:它是错误的。所以我们只是删除它。

(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))

这将允许在正文中使用多个表达式。我们可以更进一步:我们可以允许它指定迭代次数和 return 值`:

(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