Reputation: 15710
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
>
Upvotes: 26
Views: 29802
Reputation: 79073
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 define
d 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 define
s, and some won't. Also, you're only supposed to use set!
on a variable that's already been define
d. Again, how strictly this rule is enforced depends on the implementation.
Upvotes: 44
Reputation: 3233
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 define
s inside of certain constructs are actually treated as letrec
s.
Upvotes: 7
Reputation: 56752
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.
Upvotes: 3
Reputation: 18960
When you use lexical bindings you do not define
them:
(let ((x 1))
(set! x (+ x 1))
x)
Upvotes: 3