In Scheme, what's the point of "set!"?
Solution 1
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.
Solution 2
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.
Solution 3
When you use lexical bindings you do not define
them:
(let ((x 1))
(set! x (+ x 1))
x)
Solution 4
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.
Related videos on Youtube
HS.
Updated on July 09, 2022Comments
-
HS. almost 2 years
What's the point of using the
set!
assignment operator in scheme? Why not justrebind
a variable to a new value usingdefine
?> (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 >
-
Rohit Shinde about 9 yearsHow would you design a loop counter in Scheme?
-
RnBandCrunk over 5 years@RohitShinde bit late, but you have to accumulate the counter in the function signature. A loop per se is non existent in Scheme, but recursive functions are. So you can use recursive functions to make a loop, and to make a "loop" counter you'd need to have your counter in the parameter list of your function. And everytime you make a recursive call you just decrement your counter first. The keyword here is "accumulative recursion"