今天我遇到了一个相当意外的行为,这与我对Racket的可变性了解的完全相反(我认为)。
#lang racket
(define num 8)
;(define num 9)
取消第二行注释会返回错误"module: duplicate definition for identifier in: num"
,这是可以预期的。毕竟,define
应该将已经定义的值视为不可变的。
但是,这对我来说毫无意义:
#lang racket
(define num 8)
num
(define define 1)
(+ define define)
它返回8
和2
,但是...
define
不是set!
,并且不应允许重新定义已经定义的内容,例如define
本身。define
是一项核心语言功能,并且已经明确定义,否则我根本无法使用num
。有什么作用?为什么define
用于创建不可变值,而不是不可变值呢? 这是怎么回事?
答案 0 :(得分:2)
(define define 1)
此示例显示了阴影,它不同于突变。
Shadowing在内存中分配新的位置。它不会变异现有的。
具体来说,新的define
遮盖了球拍中的define
。
所有带有局部范围标记的语言都可以进行阴影处理,例如:
> (define x 10)
> (define (f x) ; x shadowed in function f
(displayln x)
(set! x 2) ; (local) x mutated
(displayln x))
> (f 1)
1
2
; local x is out of scope now
> (displayln x) ; original x unmutated
10
对于另一个示例,
(define num 8)
;(define num 9)
这表明您不能在同一范围内遮挡某些物体,这在其他语言中也是标准的,例如:
> (define (g x x) x) ; cant have two parameters named x
答案 1 :(得分:0)
顶级定义绑定源自宏扩展的标识符时,由于为扩展生成的是新作用域,因此该定义仅捕获由同一扩展生成的标识符的使用。
换句话说,其他模块所需的转换器(宏)可以重新定义,因为它们是由宏扩展器扩展出来的(因此问题不完全是可变性),而且,因为球拍是关于可扩展性,没有保留关键字,可以通过宏(或函数)将附加功能添加到当前的define
中,这就是可以重新定义它的原因。
define
被定义为此格式的宏-请参见here。
#lang racket
(module foo1 racket
(provide foo1)
(define-syntaxes (foo1)
(let ([trans (lambda (syntax-object)
(syntax-case syntax-object ()
[(_) #'1]))])
(values trans))))
; ---
(require 'foo1)
(foo1)
; => 1
(define foo1 9)
(+ foo1 foo1)
; => 18