程序仅在定义两次时才有效
Procedure works only if defined twice
我定义了一个 map
过程和一个 square
过程。 square
过程工作正常,但 map
过程只有在定义两次时才有效。
给定以下代码:
; Squares a number.
(define square (lambda (n)
(* n n)
))
; Applies function f on all elements of l.
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
此程序在执行时崩溃:
> (map '(1 2 3) square)
; mcar: contract violation
; expected: mpair?
; given: #<procedure:square>
; [,bt for context]
然而,给定以下代码,该程序按预期运行。唯一的区别是 map
现在被定义了两次。
; Squares a number.
(define square (lambda (n)
(* n n)
))
; Applies function f on all elements of l.
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
这个版本工作正常:
> (map '(1 2 3) square)
{1 4 9}
是什么导致了这个问题,应该如何解决?
map
是一个标准的 Scheme 函数。当您第一次定义该函数时,它显然是在尝试调用标准函数,而不是您对它的重新定义。由于标准函数以相反的顺序接受参数 (map function list)
,因此会出错。第二次定义它时,它会在环境中找到你的功能,所以一切正常。
最好的解决方案是使用不与标准函数冲突的不同名称。
我无法重现您的问题。具体来说,我在 DrRacket 中 运行 这个程序:
#lang r5rs
; Squares a number.
(define square (lambda (n)
(* n n)
))
; Applies function f on all elements of l.
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
然后,在互动中 window,我 运行
> (map '(3 4 5) square)
...并得到结果:
(mcons 9 (mcons 16 (mcons 25 '())))
您能否提供更多信息以帮助重现您的问题? (你提到 mcons 清楚地表明你正在 运行 使用 racket,使用命令行来编写这段代码,但我猜你的加载方式和 运行宁你的代码。)
编辑:好的,我现在可以通过将这些表达式一个一个地粘贴到 REPL 中来重现这样的东西。显然已经很久没有使用顶级REPL了。无论您的问题的答案如何,更高级别的答案是:不要将表达式粘贴到 REPL 中。用 Matthew Flatt(Racket 的主要实现者)的话来说,"The top level is hopeless." 使用 DrRacket 是解决这个问题的最简单方法。
编辑 2:如我所料,TL; DR:1)顶层是没有希望的。 2) 将所有代码放入模块中。
我在 Racket-Users 列表的帖子中总结了一些这种混淆。具体来说,基本问题:绑定的右侧如何不在绑定本身的范围内?
马修的回答摘录如下:
这就是问题的本质。哪些东西在a的范围内
顶级定义?
例如,在 f
的绑定范围内引用 f
在
(define (g x) (f x))
(define (f x) x)
?
在
怎么样
(begin
(define (g x) (f x))
(define (f x) x))
?
或在
(expand '(define (f x) x))
(define (g x) (f x))
或
(begin
(expand '(define (f x) x))
(define (g x) (f x)))
?
Racket 中的规则是顶级 define
不会改变
标识符的绑定,直到 define
被评估。所以,在
(define (map x) ... map ...)
对 map
的引用是 expanded/compiled 在 map
的位置
指的是模块导入,而不是名为 map
的变量。到时候
定义被评估,重定向 map
的含义为时已晚
作为对导入的引用。
还有其他选择,但我认为没有其他选择
最终变得更好或更一致。顶层是
没希望了。
模块的表现明显更好,部分原因是 a 的范围
定义很明确:从模块的开始到结束。
此时,您可能会振振有词地问 应该如何与 Racket 交互。有几个不错的选择:
1) 使用 DrRacket。我怎么推荐都不为过。
2) 使用命令行和 "require" 而不是 "load"。 "load",不要把它说得太细,是该语言旧版本的半损坏保留。
所以,例如,我可以将这段代码放在一个名为 'a.rkt':
的文件中
#lang r5rs
; Squares a number.
(define square (lambda (n)
(* n n)
))
; Applies function f on all elements of l.
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
然后,我启动racket和'require'这个模块,然后用',enter'进入模块:
hardy:/tmp clements> racket
Welcome to Racket v6.11.0.6.
> (require "a.rkt")
> ,enter "a.rkt"
"a.rkt"> (map '(3 4 5) square)
(mcons 9 (mcons 16 (mcons 25 '())))
"a.rkt">
让我再重复一遍,您只需使用 DrRacket 就可以避免所有这些问题。
所以...我今天学到了很多东西!谢谢!
我定义了一个 map
过程和一个 square
过程。 square
过程工作正常,但 map
过程只有在定义两次时才有效。
给定以下代码:
; Squares a number.
(define square (lambda (n)
(* n n)
))
; Applies function f on all elements of l.
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
此程序在执行时崩溃:
> (map '(1 2 3) square)
; mcar: contract violation
; expected: mpair?
; given: #<procedure:square>
; [,bt for context]
然而,给定以下代码,该程序按预期运行。唯一的区别是 map
现在被定义了两次。
; Squares a number.
(define square (lambda (n)
(* n n)
))
; Applies function f on all elements of l.
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
这个版本工作正常:
> (map '(1 2 3) square)
{1 4 9}
是什么导致了这个问题,应该如何解决?
map
是一个标准的 Scheme 函数。当您第一次定义该函数时,它显然是在尝试调用标准函数,而不是您对它的重新定义。由于标准函数以相反的顺序接受参数 (map function list)
,因此会出错。第二次定义它时,它会在环境中找到你的功能,所以一切正常。
最好的解决方案是使用不与标准函数冲突的不同名称。
我无法重现您的问题。具体来说,我在 DrRacket 中 运行 这个程序:
#lang r5rs
; Squares a number.
(define square (lambda (n)
(* n n)
))
; Applies function f on all elements of l.
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
然后,在互动中 window,我 运行
> (map '(3 4 5) square)
...并得到结果:
(mcons 9 (mcons 16 (mcons 25 '())))
您能否提供更多信息以帮助重现您的问题? (你提到 mcons 清楚地表明你正在 运行 使用 racket,使用命令行来编写这段代码,但我猜你的加载方式和 运行宁你的代码。)
编辑:好的,我现在可以通过将这些表达式一个一个地粘贴到 REPL 中来重现这样的东西。显然已经很久没有使用顶级REPL了。无论您的问题的答案如何,更高级别的答案是:不要将表达式粘贴到 REPL 中。用 Matthew Flatt(Racket 的主要实现者)的话来说,"The top level is hopeless." 使用 DrRacket 是解决这个问题的最简单方法。
编辑 2:如我所料,TL; DR:1)顶层是没有希望的。 2) 将所有代码放入模块中。
我在 Racket-Users 列表的帖子中总结了一些这种混淆。具体来说,基本问题:绑定的右侧如何不在绑定本身的范围内?
马修的回答摘录如下:
这就是问题的本质。哪些东西在a的范围内 顶级定义?
例如,在 f
的绑定范围内引用 f
在
(define (g x) (f x))
(define (f x) x)
?
在
怎么样(begin
(define (g x) (f x))
(define (f x) x))
?
或在
(expand '(define (f x) x))
(define (g x) (f x))
或
(begin
(expand '(define (f x) x))
(define (g x) (f x)))
?
Racket 中的规则是顶级 define
不会改变
标识符的绑定,直到 define
被评估。所以,在
(define (map x) ... map ...)
对 map
的引用是 expanded/compiled 在 map
的位置
指的是模块导入,而不是名为 map
的变量。到时候
定义被评估,重定向 map
的含义为时已晚
作为对导入的引用。
还有其他选择,但我认为没有其他选择 最终变得更好或更一致。顶层是 没希望了。
模块的表现明显更好,部分原因是 a 的范围 定义很明确:从模块的开始到结束。
此时,您可能会振振有词地问 应该如何与 Racket 交互。有几个不错的选择:
1) 使用 DrRacket。我怎么推荐都不为过。 2) 使用命令行和 "require" 而不是 "load"。 "load",不要把它说得太细,是该语言旧版本的半损坏保留。
所以,例如,我可以将这段代码放在一个名为 'a.rkt':
的文件中#lang r5rs
; Squares a number.
(define square (lambda (n)
(* n n)
))
; Applies function f on all elements of l.
(define map (lambda (l f)
(cond
((null? l) '())
(else (cons (f (car l)) (map (cdr l) f)))
)
))
然后,我启动racket和'require'这个模块,然后用',enter'进入模块:
hardy:/tmp clements> racket
Welcome to Racket v6.11.0.6.
> (require "a.rkt")
> ,enter "a.rkt"
"a.rkt"> (map '(3 4 5) square)
(mcons 9 (mcons 16 (mcons 25 '())))
"a.rkt">
让我再重复一遍,您只需使用 DrRacket 就可以避免所有这些问题。
所以...我今天学到了很多东西!谢谢!