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)

它returns82,但是...

  1. define 不是 set!,并且不应允许重新定义已定义的内容,例如 define 本身。
  2. 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