我有一个简单的程序:
(import (rnrs))
(define (abs x)
(cond ((> x 0) x)
((= x 0) 0)
((< x 0) (- x))
))
(define (square x)
(* x x))
(define (sum-sq x y)
(+ (square x) (square y)))
(display
(sum-sq (read) 3))
当我运行它时,我有一个异常;我做错了什么?
/home#scheme-script/home/scheme/main.ss
异常:body中abs的多个定义(顶级程序#<annotation/home/scheme/main.ss[0:15](导入(…((><annotation/home/scheme/main.ss([17:122](define(…((…((><注释/home/scheme/main.ss[124:156](define(…((…((><注释/home/scheme/main.ss[158:210](define(…((…((><注释/home/scheme/main.ss[21:244](显示(…((>第1行附近,第1个字符/home/scheme/main.ss
错误消息非常明确:您正在重新定义abs
,这是一个内置过程。根据使用的Scheme解释器的不同,这可能是一个问题——特别是,您不能在Chez Scheme中重新定义过程。只需删除abs
,它就已经由该语言提供了。
在R6RS方案中重新定义顶级程序中的变量是非法的。OP已经使用CCD_ 3执行了脚本;在Chez Scheme中,scheme-script
等效于将文件视为顶级程序的scheme --program
。当您尝试定义时,可以在REPL中重新定义内容,除非您将代码包装为top-level-program
形式
scheme --script
将文件视为shell脚本,而scheme-script
(即scheme --program
(将其视为顶级程序。要证明OP的问题是文件被当作顶级程序处理的结果,请使用scheme --script
运行它,然后将发布的代码包装成(top-level-program ...)
形式,并尝试使用scheme --script
再次运行。第一次尝试将成功执行,第二次尝试将再次引发异常。
OP问题的一个解决方案是使用scheme --script
而不是scheme-script
(或scheme --program
(。当然,可以简单地使用内置的abs
过程,或者将新过程重命名为例如my-abs
。
但是,有时您确实希望使用以前由需要导入的某个库声明的标识符。对于这种情况,存在except
。以下是使用import
形式的except
的OP代码版本:
(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*<绑定><正文>(语法
语法:<绑定>必须具有表格
((<variable1><init1>(…(,
其中每个<init>是表达式,并且<身体>如中所述第11.3条任何变量在<变量>s。
因此,标识符不能多次导入,既不能导入也不能定义,也不能在库或顶级程序中定义。OP代码通过导入标识符的定义和在顶级程序中重新定义该标识符来违反这一点。