Подтвердить что ты не робот

На Схеме, какой смысл "установить!"?

Какой смысл использовать оператор присваивания set! в схеме? Почему не просто rebind переменная к новому значению с помощью define?

> (define x 100)
> (define (value-of-x) x) ;; value-of-x closes over "x"
> x
100
> (value-of-x)
100
> (set! x (+ x 1))
> x
101
> (value-of-x)
101
> (define x (+ x 1))
> x
102
> (value-of-x)
102
> 
4b9b3361

Ответ 1

Хотя оба define и set! будут переопределять значение, когда в той же области действия, они имеют две разные вещи, когда область отличается. Вот пример:

(define x 3)

(define (foo)
  (define x 4)
  x)

(define (bar)
  (set! x 4)
  x)

(foo) ; returns 4
x     ; still 3
(bar) ; returns 4
x     ; is now 4

Как вы можете видеть, когда мы создаем новую лексическую область (например, когда мы define функция), любые имена, определенные в этой области, маскируют имена, которые появляются в охватывающей области. Это означает, что когда мы define d x до 4 в foo, мы действительно создали новое значение для x, которое затеняет старое значение. В bar, так как foo не существует в этой области, set! обращается к охватывающей области, чтобы найти и изменить значение x.

Кроме того, как говорили другие люди, вы должны только define указывать имя в области. Некоторые реализации позволят вам уйти с несколькими define s, а некоторые - нет. Кроме того, вы должны использовать set! для переменной, которая уже была define d. Опять же, насколько строго соблюдается это правило, зависит от реализации.

Ответ 2

Обычно не разрешается define изменять переменную более одного раза. Большинство REPL разрешают это для удобства, когда вы пытаетесь разобраться, но если вы попытаетесь сделать это в программе Scheme, это даст вам ошибку.

Например, в mzscheme программа

#lang scheme
(define x 1)
(define x 2)

дает ошибку

test.ss:3:8: module: duplicate definition for identifier at: x in: (define-values (x) 2)

Кроме того, define имеет другое значение при использовании внутри других контекстов. Программа

#lang scheme
(define x 1)
x
(let ()
  (define x 2)
  x)
x

имеет выход

1
2
1

Это связано с тем, что define внутри некоторых конструкций фактически обрабатывается как letrec s.

Ответ 3

Когда вы используете лексические привязки, вы не define их:

(let ((x 1))
  (set! x (+ x 1))
  x)

Ответ 4

Когда вы используете define, вы создаете новую переменную с новым значением, а старая переменная все еще существует со старым значением; он просто скрыт новым. В командной строке вы не видите разницы в настройке!, но определение не будет использоваться, например. счетчик циклов в императивной программе.