编译时 Scheme 在宏中找不到函数
Scheme can't find function inside macro while compile
我有这样的示例代码:
#!/usr/bin/guile -s
!#
(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)
它 运行 但我从编译器那里得到错误
ERROR: Unbound variable: process
宏中的函数应该是允许的,为什么我会得到这个错误?
宏 中的函数 允许在 Guile 和大多数其他 Scheme 方言中使用。
但是,关键的问题是:宏在扩展过程中可以调用哪些函数?
可以这样想:当编译器处理您的代码时,它首先专注于将您的源代码变成将来某个时候可以 运行 的东西。但是编译器在编译它们时可能不一定能够立即执行这些相同的函数,同时您的宏正在 运行 宁和扩展源代码。
- 为什么没有这样的功能?好吧,一个例子是:如果函数体 使用了 您正在定义的宏怎么办?那么你会遇到一点 chicken/egg 问题。该函数需要 运行 编译宏(因为主体中的宏使用需要在编译时扩展)......但是宏需要可用的编译函数才能 运行!
(此外,可能有一些函数您 只 希望在编译时可用,作为您的宏的助手,但您不想成为在 运行 时间可用,因此在部署时它不会包含在您的程序可执行文件中,因为这会浪费 space 在已部署的二进制文件中。)
我最喜欢的一篇描述这个问题的论文,以及 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)
我有这样的示例代码:
#!/usr/bin/guile -s
!#
(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)
它 运行 但我从编译器那里得到错误
ERROR: Unbound variable: process
宏中的函数应该是允许的,为什么我会得到这个错误?
宏 中的函数 允许在 Guile 和大多数其他 Scheme 方言中使用。
但是,关键的问题是:宏在扩展过程中可以调用哪些函数?
可以这样想:当编译器处理您的代码时,它首先专注于将您的源代码变成将来某个时候可以 运行 的东西。但是编译器在编译它们时可能不一定能够立即执行这些相同的函数,同时您的宏正在 运行 宁和扩展源代码。
- 为什么没有这样的功能?好吧,一个例子是:如果函数体 使用了 您正在定义的宏怎么办?那么你会遇到一点 chicken/egg 问题。该函数需要 运行 编译宏(因为主体中的宏使用需要在编译时扩展)......但是宏需要可用的编译函数才能 运行!
(此外,可能有一些函数您 只 希望在编译时可用,作为您的宏的助手,但您不想成为在 运行 时间可用,因此在部署时它不会包含在您的程序可执行文件中,因为这会浪费 space 在已部署的二进制文件中。)
我最喜欢的一篇描述这个问题的论文,以及 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)