Изменчивость основных функций в Racket - PullRequest
2 голосов
/ 31 октября 2019

Сегодня я столкнулся с довольно неожиданным поведением, и оно совершенно противоречило тому, что (я думал) я знал об изменчивости в 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,но ...

  1. define не является set! и не должно допускать переопределения чего-то уже определенного, такого как define.
  2. define isбазовая языковая функция, и она уже четко определена, или я вообще не смогу использовать num.

Что дает? Почему define, который используется для создания неизменных значений, не является неизменным для себя? Что здесь происходит?

Ответы [ 2 ]

2 голосов
/ 01 ноября 2019
(define define 1)

В этом примере показано затенение, которое отличается от мутации.

Затенение выделяет новые места в памяти. Он не изменяет существующие.

Конкретно, новые define затеняют define от Racket.

Все языки с обозначением локальной области видимости позволяют затенять, например:

> (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
0 голосов
/ 31 октября 2019

Когда определение верхнего уровня связывает идентификатор, который исходит из макроподключения, определение захватывает только те идентификаторы, которые сгенерированы тем же расширением из-за новой области, сгенерированной для расширения.

Другими словами, преобразователи (макросы), которые требуются от других модулей, могут быть переопределены, потому что они расширяются с помощью макроэкспандера (поэтому проблема не совсем в изменчивости). Более того, поскольку ракетка связана только с расширяемостью, нет зарезервированных ключевых слов и дополнительные функции могут быть добавлены к текущему define через макрос (или функцию), поэтому его можно переопределить.

define определяется как макрос этого вида- см. здесь .

#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
...