微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决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) 返回 11 的值为 1

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

这是一个运行时错误。

但是......你为什么使用evaleval 对几乎所有你能想到的问题来说都是一个糟糕的、糟糕的解决方案,除非该问题的解决方案被称为“代码注入攻击”,在这种情况下,它不仅糟糕:它是错误的。所以我们只需将其删除。

(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 举报,一经查实,本站将立刻删除。