4.9 Assignment: set!
Assign to a variable using set!:
(set! id expr)
(define (make-running-total) (let ([n 0]) (lambda () (set! n (+ n 1)) n))) (define win (make-running-total)) (define lose (make-running-total))
As in any modern language, assigning to a shared identifier is no substitute for passing an argument to a procedure or getting its result.
Really awful example:
(define (greet name) (string-append "Hello, " name)) > (greet "John")
> (greet "Anna")
A sequence of assignments to a local variable is far inferior to nested bindings.
Using assignment to accumulate results from an iteration is bad style. Accumulating through a loop argument is better.
Somewhat bad example:
Better (use an existing function) example:
Good (a general approach) example:
For cases where stateful objects are necessary or appropriate, then implementing the object’s state with set! is fine.
All else being equal, a program that uses no assignments or mutation is always preferable to one that uses assignments or mutation. While side effects are to be avoided, however, they should be used if the resulting code is significantly more readable or if it implements a significantly better algorithm.
The use of mutable values, such as vectors and hash tables, raises fewer suspicions about the style of a program than using set! directly. Nevertheless, simply replacing set!s in a program with vector-set!s obviously does not improve the style of the program.
4.9.2 Multiple Values: set!-values
The set!-values form assigns to multiple variables at once, given an expression that produces an appropriate number of values:
(set!-values (id ...) expr)