Macros 如何从Chicken Scheme宏调用其他宏?

Macros 如何从Chicken Scheme宏调用其他宏?,macros,scheme,chicken-scheme,define-syntax,Macros,Scheme,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中,等效代码不起

我正试图从普通的口齿不清转变为,但有很多问题

我目前的问题是:如何编写一个调用其他宏的宏(可能使用
定义语法
?)

例如,在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))))))
无法从
其他
宏调用
附加到
宏。我收到一个错误,说明
附加到
的“变量”未定义

根据我从Google和其他来源收集到的所有信息,宏是在一个封闭的环境中评估的,没有访问其他代码的权限。本质上,当对宏求值时,除了内置的Scheme函数和宏之外,不存在其他任何东西。我曾经尝试过使用
er宏转换器
语法大小写
(现在在Chicken中已经被弃用)甚至
过程宏
模块

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

我调查了其他方案的实现,但没有更多的运气。看来这根本做不到


有人能帮我一下吗?

看起来你把扩展时间和运行时间搞混了。您给出的
语法规则
示例将扩展到let+集,这意味着追加将在运行时发生

语法规则
只需将输入重写为给定的输出,并展开宏,直到没有更多可展开的内容。如果要在展开时实际执行某些计算,唯一的方法是使用过程宏(这也是
defmacro
CL示例中发生的情况)

在Scheme中,求值级别是严格分开的(这使单独编译成为可能),因此过程可以使用宏,但宏本身不能使用在同一段代码中定义的过程(或宏)。可以从模块中加载过程和宏,以便在过程宏中使用。在语法扩展时定义要运行的东西时,通过将它们包装在中,支持是有限的

例如,参见或。马修·弗拉特的论文更详细地解释了这背后的理论

“相分离”思想在方案领域相对较新(请注意,Flatt论文是2002年的),因此您会发现方案社区中有相当多的人仍然对此感到困惑。它之所以是“新的”(尽管Scheme已经有了宏很长一段时间),是因为自R6RS以来,过程宏才成为标准的一部分(并且在R7RS中恢复,因为
语法大小写
相当有争议),所以严格指定它们的需要直到现在还不是一个问题。对于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)

如果您将
附加的定义放在它自己的模块中,并且
用于语法
它,那么这也应该起作用。这还允许您在代码体中定义的宏中以及在过程中使用相同的模块,只需在
使用
语法使用
表达式中都要求它。

做任何比
语法规则
宏更复杂的事情都是非标准方案,因此,尽管在许多特定的方案中,你想做的事情是完全可能的,但在它们之间,实现的方式可能会有很大的差异。如果你想问这类问题,最好选择一个具体的方案实现,并询问如何在其中复制它。@AlexisKing谢谢,我已经修改了我的问题,将重点放在一个实现上。我不太理解这个问题。也许你可以给出一个普通的Lisp示例,但你无法使用CHICKEN?@sjaman我已经添加了一个普通的Lisp示例。谢谢,现在更清楚了!这是一个非常有用的回答,谢谢。所以有点像那样?是的。然而,在那个特定的示例中,您当然不需要使用er宏转换器。只有当您需要执行副作用或希望在编译时构造标识符或常量时,才需要这样做。(在只需要模式匹配和重新排列输入表达式的情况下,只需使用
语法规则