(set! var expr)Example:
(define x 10) (write x) (set! x (+ x 1)) (write x)
You can only use set! on a variable after it's been defined.
There are also functions set-car! and set-cdr! to assign into the car or cdr of a cons cell. Finally, there is a special form do for iteration.
Example:
(define x '(1 2 3 4)) (write x) ; prints (1 2 3 4) (set-car! x 100) (write x) ; prints (100 2 3 4) (set-cdr! x ()) (write x) ; prints (100)Making a circular list:
(define circ '(a b)) (set-cdr! (cdr circ) circ)When you pass a list to a function in Scheme, a reference to the list is passed, rather than a copy. Thus, if you use set-car! or set-cdr! to do list surgery inside the function, the actual parameter will be affected.
(define (change-it x) (set-car! x 'frog)) (define animals '(rabbit horse squirrel monkey)) (change-it animals)However, consider:
(define (test x) (write x) (set! x 100) (write x)) (define y '(1 2 3)) (test y) ; prints (1 2 3) then 100 (write y) ; prints (1 2 3) ... y is unaltered
First, let's see how functions can share state.
;; define the variables incr and get, and just give them null as ;; a value for now (it will be reset later) (define incr ()) (define get ()) (let ((n 0)) (set! incr (lambda (i) (set! n (+ n i)))) (set! get (lambda () n)))The variables incr and get are global variables, now bound to functions. The variable n is shared by them, but is hidden -- it is not a global variable.
Now try evaluating the following expressions:
(get) (incr 10) (get) (incr 100) (get)Now we can add dispatching to simulate a simple object. (This example is adapted from Structure and Interpretation of Computer Programs.) Here we define a bank account object, with a field my-balance, and methods balance, deposit, and withdraw.
This example is also available as a separate web page bankaccount.scm.
(define (make-account) (let ((my-balance 0)) ;; return the current balance (define (balance) my-balance) ;; make a withdrawal (define (withdraw amount) (if (>= my-balance amount) (begin (set! my-balance (- my-balance amount)) my-balance) "Insufficient funds")) ;; make a deposit (define (deposit amount) (set! my-balance (+ my-balance amount)) my-balance) ;; the dispatching function -- decide what to do with the request (define (dispatch m) (cond ((eq? m 'balance) balance) ((eq? m 'withdraw) withdraw) ((eq? m 'deposit) deposit) (else (error "Unknown request -- MAKE-ACCOUNT" m)))) dispatch))Note that the variable my-balance is local to the make-account function.
Using the account:
(define acct1 (make-account)) (define acct2 (make-account)) ((acct1 'balance)) => 0 ((acct1 'deposit) 100) => 100 ((acct1 'withdraw) 30) => 70 ((acct1 'withdraw) 200) => "Insufficient funds" ;; acct2 is a different account from acct1! ((acct2 'balance)) => 0