Chez Scheme:顶层宏导入
Chez Scheme: macro import at top level
我正在 运行ning Chez Scheme 9.5 并尝试在中定义语法转换器
图书馆。这是一个例子:
(library (forlib)
(export for)
(import (rnrs (6)))
(define-syntax for
(syntax-rules (in)
[(for x in lst body1 body2 ...)
(for-each (lambda (x) body1 body2 ...) lst)])))
我将其保存在同一目录中的文件 forlib.ss
和 运行 chez
中。
然后在 REPL 中,我得到这个:
> (import (forlib))
> (for x in '(1 2 3) (display x))
Exception: invalid syntax (for x in (quote (1 2 3)) (display x))
Type (debug) to enter the debugger.
如果我将语法定义更改为
(define-syntax for
(syntax-rules ()
[(for x lst body1 body2 ...)
(for-each (lambda (x) body1 body2 ...) lst)])))
(没有 in
关键字),一切正常:
> (import (forlib))
> (for x '(1 2 3) (display x))
123
> _
返回旧定义 和 in
关键字。
如果我将测试代码放入测试文件中:
;;; test-for.ss
(import (rnrs (6))
(forlib))
(for x in '(1 2 3) (display x))
并尝试执行这个文件,结果取决于我如何执行文件。
如果我 运行 这个程序使用 chez --program
,它会按预期工作:
$ chez --program test-for.ss
123
$ _
如果我 运行 使用 chez --script
,我会得到与上面相同的错误:
$ chez --script test-for.ss
Exception: invalid syntax (for x in (quote (1 2 3)) (display x)) at line 6, char 1 of test-for.ss
$ _
这提出了两个问题:
- 为什么 REPL 和
--script
可以导入语法形式而无需
特殊关键字,但拒绝接受具有特殊关键字的语法形式
其中包含关键字?
--script
和 --program
到底有什么区别?这
用户手册说 --program
表示文件内容被解释
作为一个 rnrs 顶级程序,但对它的语义是什么保持沉默
--script
是。
最后,为了让我的困惑更完整,如果我输入上面的语法定义
直接在 REPL 中,然后一切都按预期工作:
> (define-syntax for
(syntax-rules (in)
[(for x in lst body1 body2 ...)
(for-each (lambda (x) body1 body2 ...) lst)])))
> (for x in '(1 2 3) (display x))
123
> _
那么从
直接在 REPL 中定义的库和语法转换器?
在 Chez Scheme 中,一些语义在操作模式之间有所不同。我将这些模式命名为 r6rs 和 repl。
R6RS:
- 程序(--命令行程序)
- 图书馆
回复:
- 脚本(--命令行脚本)
- 文件(使用加载过程或作为不带 --program 或 --script 的 CLI 参数)
- 当然还有 repl
对于您的具体问题,如果您希望 repl 和脚本匹配库和程序的行为,则需要从 forlib
定义并导出一个名为 in
的标识符。这可以像一个空定义一样简单,或者您可以创建一个在宏主体外部使用时抛出错误的语法定义。
简单:
(library (forlib)
(export for in)
(import (rnrs))
(define in)
(define-syntax for ...)
)
语法定义:
(library (forlib)
(export for in)
(import (rnrs))
(define-syntax in
(identifier-syntax
(error #f "Misplaced aux syntax in")))
(define-syntax for ...)
)
两者都很好;使用您喜欢的任何一个。
据我所知,repl 和 r6rs 模式之间的其他差异源于它们对表达式求值的方式。在 repl 模式下,每个表达式都是单独处理的。也就是说,Chez 读取一个表达式,计算该表达式,并可能打印结果。在 r6rs 模式下,文件的全部内容作为一个单元进行评估。明确指出,repl 模式的顶级延续是 "read, eval, maybe print, and loop",而 r6rs 模式的顶级延续是 next 表达式。
例如,此代码在 运行 作为程序或脚本时表现不同:
(import (chezscheme))
(define println)
(printf "~x\n"
(call/cc (lambda (k)
(set! println k)
1)))
(println 5)
(println 6)
另一个区别是,在 r6rs 模式下,您不能定义一个函数,然后在语法引用之外的语法案例宏扩展中使用它。
(define ($two) 2)
(define-syntax two
(lambda (x)
(syntax-case x ()
[_ ($two)])))
我正在 运行ning Chez Scheme 9.5 并尝试在中定义语法转换器 图书馆。这是一个例子:
(library (forlib)
(export for)
(import (rnrs (6)))
(define-syntax for
(syntax-rules (in)
[(for x in lst body1 body2 ...)
(for-each (lambda (x) body1 body2 ...) lst)])))
我将其保存在同一目录中的文件 forlib.ss
和 运行 chez
中。
然后在 REPL 中,我得到这个:
> (import (forlib))
> (for x in '(1 2 3) (display x))
Exception: invalid syntax (for x in (quote (1 2 3)) (display x))
Type (debug) to enter the debugger.
如果我将语法定义更改为
(define-syntax for
(syntax-rules ()
[(for x lst body1 body2 ...)
(for-each (lambda (x) body1 body2 ...) lst)])))
(没有 in
关键字),一切正常:
> (import (forlib))
> (for x '(1 2 3) (display x))
123
> _
返回旧定义 和 in
关键字。
如果我将测试代码放入测试文件中:
;;; test-for.ss
(import (rnrs (6))
(forlib))
(for x in '(1 2 3) (display x))
并尝试执行这个文件,结果取决于我如何执行文件。
如果我 运行 这个程序使用 chez --program
,它会按预期工作:
$ chez --program test-for.ss
123
$ _
如果我 运行 使用 chez --script
,我会得到与上面相同的错误:
$ chez --script test-for.ss
Exception: invalid syntax (for x in (quote (1 2 3)) (display x)) at line 6, char 1 of test-for.ss
$ _
这提出了两个问题:
- 为什么 REPL 和
--script
可以导入语法形式而无需 特殊关键字,但拒绝接受具有特殊关键字的语法形式 其中包含关键字? --script
和--program
到底有什么区别?这 用户手册说--program
表示文件内容被解释 作为一个 rnrs 顶级程序,但对它的语义是什么保持沉默--script
是。
最后,为了让我的困惑更完整,如果我输入上面的语法定义 直接在 REPL 中,然后一切都按预期工作:
> (define-syntax for
(syntax-rules (in)
[(for x in lst body1 body2 ...)
(for-each (lambda (x) body1 body2 ...) lst)])))
> (for x in '(1 2 3) (display x))
123
> _
那么从 直接在 REPL 中定义的库和语法转换器?
在 Chez Scheme 中,一些语义在操作模式之间有所不同。我将这些模式命名为 r6rs 和 repl。
R6RS:
- 程序(--命令行程序)
- 图书馆
回复:
- 脚本(--命令行脚本)
- 文件(使用加载过程或作为不带 --program 或 --script 的 CLI 参数)
- 当然还有 repl
对于您的具体问题,如果您希望 repl 和脚本匹配库和程序的行为,则需要从 forlib
定义并导出一个名为 in
的标识符。这可以像一个空定义一样简单,或者您可以创建一个在宏主体外部使用时抛出错误的语法定义。
简单:
(library (forlib)
(export for in)
(import (rnrs))
(define in)
(define-syntax for ...)
)
语法定义:
(library (forlib)
(export for in)
(import (rnrs))
(define-syntax in
(identifier-syntax
(error #f "Misplaced aux syntax in")))
(define-syntax for ...)
)
两者都很好;使用您喜欢的任何一个。
据我所知,repl 和 r6rs 模式之间的其他差异源于它们对表达式求值的方式。在 repl 模式下,每个表达式都是单独处理的。也就是说,Chez 读取一个表达式,计算该表达式,并可能打印结果。在 r6rs 模式下,文件的全部内容作为一个单元进行评估。明确指出,repl 模式的顶级延续是 "read, eval, maybe print, and loop",而 r6rs 模式的顶级延续是 next 表达式。 例如,此代码在 运行 作为程序或脚本时表现不同:
(import (chezscheme))
(define println)
(printf "~x\n"
(call/cc (lambda (k)
(set! println k)
1)))
(println 5)
(println 6)
另一个区别是,在 r6rs 模式下,您不能定义一个函数,然后在语法引用之外的语法案例宏扩展中使用它。
(define ($two) 2)
(define-syntax two
(lambda (x)
(syntax-case x ()
[_ ($two)])))