在 R6RS Scheme 的顶层程序中重新定义变量是非法的。scheme-script
OP 已使用;执行脚本 在 Chez Schemescheme-script
中相当于scheme --program
,它将文件视为顶级程序。当您尝试定义时,可以在 REPL 中重新定义内容,除非您将该代码包装在一个top-level-program
表单中。
scheme --script
将文件视为 shell 脚本,而scheme-script
(ie, scheme --program
) 将其视为顶级程序。为了证明 OP 的问题是文件被视为顶级程序的结果,请使用 运行它scheme --script
,然后将发布的代码包装在一个(top-level-program ...)
表单中并尝试再次运行scheme --script
。第一次尝试将成功执行,第二次将再次引发异常。
OP 问题的一种解决方案是使用scheme --script
代替scheme-script
(或scheme --program
)。当然,可以简单地使用内置abs
程序,或者将新程序重命名为,例如my-abs
.
但是,有时您确实确实想使用之前已被您需要导入的某个库声明的标识符。对于那种情况有except
。这是 OP 代码的一个版本,except
格式import
如下:
(import (except (rnrs) abs))
(define (abs x)
(if (< x 0) (- x) x))
(define (my-abs x)
(<))
(define (square x) (* x x))
(define (sum-sq x y)
(+ (square x) (square y)))
(display "Enter a number: ")
(let ((x (read)))
(display x) (display "^2 + 3^2 = ") (display (sum-sq x 3)) (newline))
(display "Enter a number: ")
(let ((x (read)))
(display "|") (display x) (display "| = ") (display (abs x)) (newline))
;;; Easier with Chez Scheme `format`, which can be made available by
;;; changing the `import` form at the top to:
;;;
;;; (import (except (chezscheme) abs))
;; (display "Enter a number: ")
;; (let ((x (read)))
;; (format #t "~A^2 + 3^2 = ~A~%" x (sum-sq x 3)))
;; (display "Enter a number: ")
;; (let ((x (read)))
;; (format #t "|~A| = ~A~%" x (abs x)))
该程序导入从rnrs
库中导出的所有标识符,除了abs
. 然后顶层程序可以自由定义abs
标识符。
$ scheme-script top-level.ss
Enter a number: 4
4^2 + 3^2 = 25
Enter a number: -42
|-42| = 42
标准怎么说
顶级程序就像一个库,只是它不能包含export
表单。从R6RS 7.1。图书馆形式:
...没有标识符可以多次导入,多次定义,或者既定义又导入。
规范继续:
变量定义的表达式是从左到右计算的,就好像在一个隐式的letrec* ....
但是,到11.4.6。绑定结构,letrec*
形式为:
( letrec* <bindings> <body>)语法
语法:<Bindings> 必须具有格式
((<variable1> <init1>) ...),
其中每个 <init> 都是一个表达式,而 <body> 如第 11.3 节所述。任何变量都不得在 <variable>s 中出现多次。
所以一个标识符不能被多次导入,无论是导入和定义,还是在库或顶级程序中定义和重新定义。OP 代码通过导入标识符的定义和在顶级程序中重新定义该标识符来违反这一点。