我正在运行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
$ _
这引起了两个问题:
--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
> _
那么从APL导入的语法转换器在REPL中有什么不同 直接在REPL中定义的库和语法转换器?
答案 0 :(得分:3)
在Chez Scheme中,某些语义在操作模式之间有所不同。我将这些模式命名为r6rs和repl。
R6RS:
REPL:
对于您的特定问题,如果您希望repl和脚本与库和程序的行为相匹配,则需要从in
定义并导出名为forlib
的标识符。这可以像一个空定义一样简单,也可以创建一个语法定义,该定义在宏主体之外使用时会引发错误。
简单:
(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模式的最高级延续是“读取,评估,也许打印和循环”,而r6rs模式的最高级延续是下一个表达式。 例如,以下代码在作为程序或脚本运行时的行为会有所不同:
(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)])))