2

我正在尝试从 Common Lisp 转移到Chicken Scheme,并且遇到了很多问题。

我目前的问题是:如何编写define-syntax调用其他宏的宏(大概使用?)?

例如,在 Common Lisp 中,我可以这样做:

(defmacro append-to (var value)
 `(setf ,var (append ,var ,value)))

(defmacro something-else ()
 (let ((values (list))
  (append-to values '(1)))))

而在 Scheme 中,等效代码不起作用:

(define-syntax append-to
 (syntax-rules ()
  ((_ var value)
   (set! var (append var value)))))

(define-syntax something-else
 (syntax-rules ()
  ((_)
   (let ((values (list)))
    (append-to values '(1))))))

append-to不能从宏调用宏something-else。我收到一条错误消息,说append-to“变量”未定义。

根据我从谷歌和其他来源收集到的所有信息,宏是在封闭环境中评估的,无法访问其他代码。本质上,在评估宏时,除了内置的 Scheme 函数和宏之外,什么都不存在。我已经尝试使用er-macro-transformer, syntax-case(无论如何现在在 Chicken 中已弃用)甚至procedural-macros模块。

当然,宏的全部目的是它们建立在其他宏之上,以避免重复代码。如果必须单独编写宏,那么在我看来,它们几乎毫无用处。

我调查了其他方案的实现,但没有更多的运气。似乎它根本无法完成。

有人可以帮我解决这个问题吗?

4

1 回答 1

4

看起来您将扩展时间与运行时间混淆了。syntax-rules您给出的示例将扩展为 let+set,这意味着追加将在运行时发生。

syntax-rules只需将输入重写为给定的输出,扩展宏直到没有更多可扩展的内容。如果您想在扩展时实际执行一些计算,唯一的方法是使用过程宏(这也是您的defmacroCL 示例中发生的情况)。

在 Scheme 中,评估级别是严格分离的(这使得单独编译成为可能),因此一个过程可以使用宏,但宏本身不能使用在同一段代码中定义的过程(或宏)。您可以使用use-for-syntax从模块加载过程和宏以用于过程宏。通过将它们包装在begin-for-syntax中来定义在语法扩展时运行的东西的支持有限。

例如,请参阅此 SO questionikarus-users 邮件列表上的此讨论。Matthew Flatt 的论文可组合和可编译的宏更详细地解释了这背后的理论。

“相分离”思想在 Scheme 世界中相对较新(请注意,Flatt 论文是从 2002 年开始的),因此您会发现 Scheme 社区中仍有不少人对此感到困惑。它是“新”的原因(尽管 Scheme 已经有很长一段时间的宏)是程序宏自 R6RS 以来才成为标准的一部分(并在 R7RS 中恢复,因为syntax-case相当有争议),因此需要严格指定它们直到现在都不是问题。对于 Scheme 的更多“传统” Lispy 实现,编译时和运行时都混合在一起,这从来都不是问题。您可以随时运行代码。

回到您的示例,如果您正确分离各个阶段,它可以正常工作:

(begin-for-syntax
  (define-syntax append-to
    (ir-macro-transformer
      (lambda (e i c)
        (let ((var (cadr e))
              (val (caddr e)))
          `(set! ,var (append ,var ,val)))))) )

(define-syntax something-else
  (ir-macro-transformer
    (lambda (e i c)
      (let ((vals (list 'print)))
        (append-to vals '(1))
        vals))))

(something-else) ; Expands to (print 1)

如果您将定义放在append-to它自己的模块中,并且您将其放入use-for-syntax,那也应该可以。这也将允许您在代码体和过程中定义的宏中使用相同的模块,只需在 a 和表达式中都需要use use-for-syntax

于 2016-08-08T12:49:12.840 回答