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