Chez Scheme:顶级宏导入

时间:2019-01-13 22:57:52

标签: scheme r6rs chez-scheme

我正在运行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
> _

那么从APL导入的语法转换器在REPL中有什么不同 直接在REPL中定义的库和语法转换器?

1 个答案:

答案 0 :(得分:3)

在Chez Scheme中,某些语义在操作模式之间有所不同。我将这些模式命名为r6rs和repl。

R6RS:

  • 程序(-命令行上的程序)
  • 图书馆

REPL:

  • 脚本(命令行上的--script)
  • 文件(使用加载过程或不带--program或--script的CLI参数)
  • 当然还有代表

对于您的特定问题,如果您希望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)])))