异常:主体中函数的多个定义
Exception: multiple definitions for function in body
我有一个简单的程序:
(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
Exception: multiple definitions for abs in body (top-level-program
#<annotation /home/scheme/main.ss[0:15] (import (...))> #<annotation /home/scheme/main.ss)[17:122] (define (...) (...))> #<annotation
/home/scheme/main.ss[124:156] (define (...) (...))> #<annotation
/home/scheme/main.ss[158:210] (define (...) (...))> #<annotation
/home/scheme/main.ss[212:244] (display (...))> near line 1, char 1 of
/home/scheme/main.ss
错误消息非常明确:您正在重新定义 abs
,这是一个内置过程。根据所使用的 Scheme 解释器,这可能是个问题 - 特别是,您不能在 Chez Scheme 中重新定义过程。只需删除 abs
,它已由语言提供。
R6RS Scheme在顶层程序中重新定义变量是非法的。 OP 已使用 scheme-script
执行脚本;在 Chez Scheme 中 scheme-script
等同于 scheme --program
,它将文件视为顶级程序。当您尝试定义时,可以在 REPL 中重新定义内容,除非您将该代码包装在 top-level-program
形式中。
scheme --script
将文件视为 shell 脚本,而 scheme-script
(即 scheme --program
)将其视为顶级程序。为了证明 OP 的问题是文件被视为顶级程序的结果,运行 它使用 scheme --script
,然后将发布的代码包装在 (top-level-program ...)
形式并尝试 运行ning 再次与 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. Library form:
... no identifier can be imported multiple times, defined multiple times, or both defined and imported.
规范继续:
The expressions of variable definitions are evaluated from
left to right, as if in an implicit letrec*....
但是,通过 11.4.6. Binding constructs,以 letrec*
形式:
(letrec* <bindings> <body>) syntax
Syntax: <Bindings> must have the form
((<variable1> <init1>) ...),
where each <init> is an expression, and <body> is as described in
section 11.3. Any variable must not appear more than once in the
<variable>s.
所以一个标识符不能多次导入,导入和定义,或者在库或顶级程序中定义和重新定义。 OP 代码违反了这一点,既导入了标识符的定义,又在顶级程序中重新定义了该标识符。
我有一个简单的程序:
(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
Exception: multiple definitions for abs in body (top-level-program #<annotation /home/scheme/main.ss[0:15] (import (...))> #<annotation /home/scheme/main.ss)[17:122] (define (...) (...))> #<annotation /home/scheme/main.ss[124:156] (define (...) (...))> #<annotation /home/scheme/main.ss[158:210] (define (...) (...))> #<annotation /home/scheme/main.ss[212:244] (display (...))> near line 1, char 1 of /home/scheme/main.ss
错误消息非常明确:您正在重新定义 abs
,这是一个内置过程。根据所使用的 Scheme 解释器,这可能是个问题 - 特别是,您不能在 Chez Scheme 中重新定义过程。只需删除 abs
,它已由语言提供。
R6RS Scheme在顶层程序中重新定义变量是非法的。 OP 已使用 scheme-script
执行脚本;在 Chez Scheme 中 scheme-script
等同于 scheme --program
,它将文件视为顶级程序。当您尝试定义时,可以在 REPL 中重新定义内容,除非您将该代码包装在 top-level-program
形式中。
scheme --script
将文件视为 shell 脚本,而 scheme-script
(即 scheme --program
)将其视为顶级程序。为了证明 OP 的问题是文件被视为顶级程序的结果,运行 它使用 scheme --script
,然后将发布的代码包装在 (top-level-program ...)
形式并尝试 运行ning 再次与 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. Library form:
... no identifier can be imported multiple times, defined multiple times, or both defined and imported.
规范继续:
The expressions of variable definitions are evaluated from left to right, as if in an implicit letrec*....
但是,通过 11.4.6. Binding constructs,以 letrec*
形式:
(letrec* <bindings> <body>) syntax
Syntax: <Bindings> must have the form
((<variable1> <init1>) ...),
where each <init> is an expression, and <body> is as described in section 11.3. Any variable must not appear more than once in the <variable>s.
所以一个标识符不能多次导入,导入和定义,或者在库或顶级程序中定义和重新定义。 OP 代码违反了这一点,既导入了标识符的定义,又在顶级程序中重新定义了该标识符。