На Схеме, какой смысл "установить!"?
Какой смысл использовать оператор присваивания 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
>
Ответы
Ответ 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, вы создаете новую переменную с новым значением, а старая переменная все еще существует со старым значением; он просто скрыт новым. В командной строке вы не видите разницы в настройке!, но определение не будет использоваться, например. счетчик циклов в императивной программе.