2009-02-08 9 views
19

¿Cuál es el punto de utilizar el operador de asignación set! en el esquema? ¿Por qué no solo rebind una variable a un nuevo valor usando define?En Scheme, ¿cuál es el sentido de "establecer"?

> (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 
> 

Respuesta

34

Aunque tanto define como set! redefinirán un valor cuando están en el mismo ámbito, hacen dos cosas diferentes cuando el alcance es diferente. He aquí 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 se puede ver, cuando creamos un nuevo ámbito léxico (por ejemplo, cuando nos define una función), los nombres definidos dentro de ese ámbito enmascarar los nombres que aparecen en el ámbito de inclusión. Esto significa que cuando define d x a 4 en foo, realmente creamos un nuevo valor para x que sombreaba el valor anterior. En bar, dado que foo no existe en ese ámbito, set! busca en el alcance adjunto para buscar y cambiar el valor de x.

Además, como han dicho otras personas, se supone que solo define un nombre en el ámbito. Algunas implementaciones le permitirán salirse con múltiples define s, y otras no. Además, solo debe usar set! en una variable que ya ha sido define d. De nuevo, cuán estrictamente se aplica esta regla depende de la implementación.

3

Al utilizar fijaciones léxicas que haces nodefine ellos:

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

Cuando se utiliza definir crear una nueva variable con el nuevo valor, mientras que la variable antigua todavía existe con el viejo valor; simplemente está oculto por el nuevo. En la línea de comando, no verá la diferencia para establecerlo, pero la definición no será utilizable, por ej. un contador de bucle en un programa imperativo.

+0

¿Cómo diseñaría un contador de bucles en Scheme? –

5

No suele permitirse 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 utiliza 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 es porque define s dentro de ciertas construcciones son en realidad tratados como letrec s.

Cuestiones relacionadas