In Scheme, what's the point of "set!"?

24,898

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

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 defines inside of certain constructs are actually treated as letrecs.

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.

Share:
24,898

Related videos on Youtube

HS.
Author by

HS.

Updated on July 09, 2022

Comments

  • HS.
    HS. almost 2 years

    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
    > 
    
  • Rohit Shinde
    Rohit Shinde about 9 years
    How would you design a loop counter in Scheme?
  • RnBandCrunk
    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"