language - scheme synonym
En Scheme, ¿cuál es el sentido de "establecer"? (4)
¿De qué sirve usar el set!
operador de asignación en el esquema? ¿Por qué no simplemente rebind
a rebind
una variable a un nuevo valor usando 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
>
¡Aunque ambos define
y set!
redefinirá un valor cuando están en el mismo ámbito, hacen dos cosas diferentes cuando el alcance es diferente. Aquí hay un ejemplo:
(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
Como puede ver, cuando creamos un nuevo alcance léxico (como cuando define
una función), los nombres definidos dentro de ese alcance enmascaran los nombres que aparecen en el alcance adjunto. Esto significa que cuando define
d x
a 4
en foo
, realmente creamos un nuevo valor para x
que sombreaba el valor anterior. En la bar
, ya que foo
no existe en ese ámbito, set!
mira hacia el alcance adjunto para encontrar y cambiar el valor de x
.
Además, como han dicho otras personas, solo se supone que debes define
un nombre una vez en un alcance. Algunas implementaciones le permitirán salirse con múltiples define
s, y otras no. Además, ¡se supone que solo debes usar set!
en una variable que ya se ha define
d. De nuevo, cuán estrictamente se aplica esta regla depende de la implementación.
Cuando utiliza define crea una nueva variable con el nuevo valor, mientras que la antigua sigue existiendo con el valor anterior; simplemente está oculto por el nuevo. ¡En la línea de comando no se ve la diferencia para establecer !, pero define no será utilizable, por ejemplo, para un contador de bucle en un programa imperativo.
Cuando utiliza enlaces léxicos, no los define
:
(let ((x 1))
(set! x (+ x 1))
x)
Generalmente no se permite define
una variable más de una vez. La mayoría de los REPL lo permiten por conveniencia cuando estás intentando cosas, pero si tratas de hacerlo en un programa Scheme, te dará un error.
Por ejemplo, en mzscheme, el programa
#lang scheme
(define x 1)
(define x 2)
da el error
test.ss:3:8: module: duplicate definition for identifier at: x in: (define-values (x) 2)
Además, define
tiene un significado diferente cuando se usa dentro de otros contextos. El programa
#lang scheme
(define x 1)
x
(let ()
(define x 2)
x)
x
tiene la salida
1
2
1
Esto se debe a que las define
dentro de ciertas construcciones se tratan realmente como letrec
.