球拍中核心功能的可变性

时间:2019-10-31 14:12:39

标签: racket mutability

今天我遇到了一个相当意外的行为,这与我对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)

它返回82,但是...

  1. define不是set!,并且不应允许重新定义已经定义的内容,例如define本身。
  2. define是一项核心语言功能,并且已经明确定义,否则我根本无法使用num

有什么作用?为什么define用于创建不可变值,而不是不可变值呢? 这是怎么回事?

2 个答案:

答案 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