tags:

views:

246

answers:

4

What's the point of using the set! assignment operator in scheme? Why not just rebind a variable to a new value using 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
>
+2  A: 

When you use lexical bindings you do not define them:

(let ((x 1))
  (set! x (+ x 1))
  x)
kmkaplan
+1  A: 

When you use define you create a new variable with the new value, while the old variable still exists with the old value; it is just hidden by the new one. On the command line you don't see the difference to set!, but define won't be usable for e.g. a loop counter in an imperative program.

starblue
+2  A: 

It is not usually permitted to define a variable more than once. Most REPLs allow it for convenience when you're trying things out, but if you try to do that in a Scheme program it will give you an error.

For example, in mzscheme, the program

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

gives the error

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

In addition, define has a different meaning when used inside of other contexts. The program

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

has the output

1
2
1

This is because defines inside of certain constructs are actually treated as letrecs.

Henk
+4  A: 

Though both define and set! will redefine a value when in the same scope, they do two different things when the scope is different. Here's an example:

(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

As you can see, when we create a new lexical scope (such as when we define a function), any names defined within that scope mask the names that appear in the enclosing scope. This means that when we defined x to 4 in foo, we really created a new value for x that shadowed the old value. In bar, since foo does not exist in that scope, set! looks to the enclosing scope to find, and change, the value of x.

Also, as other people have said, you're only supposed to define a name once in a scope. Some implementations will let you get away with multiple defines, and some won't. Also, you're only supposed to use set! on a variable that's already been defined. Again, how strictly this rule is enforced depends on the implementation.

Kyle Cronin