Racket 中核心函数的可变性
Mutability of core functions in Racket
我今天遇到了一个相当出乎意料的行为,它与我对 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)
它returns8
和2
,但是...
define
不是 set!
,并且不应允许重新定义已定义的内容,例如 define
本身。
define
是语言的核心特性,明明已经定义好了,不然我根本就用不了num
。
什么给了?为什么用于创建不可变值的 define
本身不是不可变的? 这里发生了什么?
当顶级定义绑定源自宏扩展的标识符时,由于为扩展生成的新范围,该定义仅捕获由同一扩展生成的标识符的使用。
换句话说,可以重新定义其他模块所需的转换器(宏),因为它们已被宏扩展器扩展(因此问题不完全是关于可变性的)此外,由于球拍是所有关于可扩展性,没有保留关键字,并且可以通过宏(或函数)将附加功能添加到当前 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
(define define 1)
此示例显示阴影,这与突变不同。
阴影在内存中分配新位置。它不会改变现有的。
具体来说,新的 define
隐藏了 Racket 的 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
我今天遇到了一个相当出乎意料的行为,它与我对 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)
它returns8
和2
,但是...
define
不是set!
,并且不应允许重新定义已定义的内容,例如define
本身。define
是语言的核心特性,明明已经定义好了,不然我根本就用不了num
。
什么给了?为什么用于创建不可变值的 define
本身不是不可变的? 这里发生了什么?
当顶级定义绑定源自宏扩展的标识符时,由于为扩展生成的新范围,该定义仅捕获由同一扩展生成的标识符的使用。
换句话说,可以重新定义其他模块所需的转换器(宏),因为它们已被宏扩展器扩展(因此问题不完全是关于可变性的)此外,由于球拍是所有关于可扩展性,没有保留关键字,并且可以通过宏(或函数)将附加功能添加到当前 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
(define define 1)
此示例显示阴影,这与突变不同。
阴影在内存中分配新位置。它不会改变现有的。
具体来说,新的 define
隐藏了 Racket 的 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