在 Guile 和大多数其他 Scheme 方言中允许宏中的函数。
然而,关键问题是:在扩展过程中宏可以调用哪些函数?
这样想:当编译器处理您的代码时,它首先专注于将您的源代码转换为可以在未来某个时间运行的东西。但是编译器可能不一定能够在编译它们时立即执行这些相同的函数,同时您的宏正在运行并通常扩展源代码。
- 为什么不提供这样的功能?好吧,一个例子是:如果函数的主体使用您正在定义的宏怎么办?然后你会有一点鸡/蛋的问题。该函数需要运行要编译的宏(因为宏在主体中的使用需要在编译时扩展)......但是宏需要编译后的函数才能运行!
(此外,您可能仅希望某些函数在编译时可用,作为宏的帮助程序,但您不希望在运行时可用, 这样在部署时它就不会包含在您的程序可执行文件中,因为这会浪费部署的二进制文件中的空间。)
我最喜欢描述这个问题的论文之一,以及 MzScheme(现在称为 Racket)采用的特定解决方案,是 Matthew Flatt 的 "You Want It When" 论文。
所以,这是任何带有过程宏系统的 Scheme 方言都必须以某种方式处理的问题,Guile 也不例外。
在 Guile 的案例中,Guile 手册中直接记录的一种修复方法是使用 eval-when 特殊形式,它允许您指定特定定义在哪些阶段可用。
(上面引用的“You Want It When”论文描述了eval-when 的一些问题,但由于它是 Guile 手册文档的内容,我现在将坚持使用它。我建议在你理解之后eval-when,然后您可以查看 Racket 的解决方案,看看 Guile 是否提供类似的解决方案。)
因此,在您的情况下,由于您希望 process 函数在编译时可用(用于宏定义),您可以编写:
#!/usr/bin/guile -s
!#
(eval-when (expand)
(define (process body)
(list 'list (map (lambda (lst)
(list 'quote (car lst)))
body))))
(defmacro macro (body)
(list 'quote (process body)))
(display (macro ((foo bar) (bar baz))))
(newline)