![]() |
![]() |
![]() |
![]() |
![]() |
Even assignment is convenient and easy to understand, it has substantial drawback. See SICP: 3.1 Assignment and Local State and Why Functional Programming Matters.
Forms for assignment defined in R5RS are set!, set-car!, set-cdr!, string-set!, vector-set! and etc. In addition there are several implementation depending assignment forms. As assignment changes values of parameters, it is called destructive. In Scheme, names of destructive operators end with ! to warn programmers.
(define var 1) (set! var (* var 10)) var ⇒ 10 (let ((i 1)) (set! i (+ i 3)) i) ⇒ 4
The let, lambda, and letrec form make closures. The arguments of lambda expression are valid in the function definition. As let is a syntax sugar for lambda, the same thing happens.
(define bank-account (let ((balance 10)) (lambda (n) (set! balance (+ balance n)) balance)))The procedure assigns (+ balance n) to the balance.
(bank-account 20) ; donating 20 dollars ;Value: 30 (bank-account -25) ; withdrawing 25 dollars ;Value: 5
As you can write procedures that returns a procedure using Scheme,
you can write a function that create 'bank account'.
This example implies that it is easy to make an object oriented (OO) language using functional programming language.
In fact, only few more is required from here to make an OO language.
(define (make-bank-account balance) (lambda (n) (set! balance (+ balance n)) balance))
(define gates-bank-account (make-bank-account 10)) ; Gates makes a bank account by donating 10 dollars ;Value: gates-bank-account (gates-bank-account 50) ; donating 50 dollars ;Value: 60 (gates-bank-account -55) ; withdrawing 55 dollars ;Value: 5 (define torvalds-bank-account (make-bank-account 100)) ; Torvalds makes a bank account by donating 100 dollars ;Value: torvalds-bank-account (torvalds-bank-account -70) ; withdrawing 70 dollars ;Value: 30 (torvalds-bank-account 300) ; donating 300 dollars ;Value: 330
(define tree '((1 2) (3 4 5) (6 7 8 9))) (set-car! (car tree) 100) ; changing 1 to 100 tree ((100 2) (3 4 5) (6 7 8 9)) (set-cdr! (third tree) '(a b c)) ; changing '(7 8 9) to '(a b c) tree ⇒ ((100 2) (3 4 5) (6 a b c))
Enqueue is performed with following procedure (Fig. 2):
Dequeue is performed with following procedure (Fig. 3)
[code 1] shows a implementation of queue. The function enqueue! returns a queue in that the obj is added at the last of the queue. The function dequeue! removes the first item from the queue and return the first item.
[code 1]
(define (make-queue) (cons '() '())) (define (enqueue! queue obj) (let ((lobj (cons obj '()))) (if (null? (car queue)) (begin (set-car! queue lobj) (set-cdr! queue lobj)) (begin (set-cdr! (cdr queue) lobj) (set-cdr! queue lobj))) (car queue))) (define (dequeue! queue) (let ((obj (car (car queue)))) (set-car! queue (cdr (car queue))) obj))
(define q (make-queue)) ;Value: q (enqueue! q 'a) ;Value 12: (a) (enqueue! q 'b) ;Value 12: (a b) (enqueue! q 'c) ;Value 12: (a b c) (dequeue! q) ;Value: a q ;Value 13: ((b c) c)
Too much use of assignment makes your code ugly. Use assignment only it is really required with care.
I will explain about data structures used in Scheme in following several chapters.
(define (make-bank-account amount) (lambda (n) (let ((m (+ amount n))) (if (negative? m) 'error (begin (set! amount m) amount)))))
![]() |
![]() |
![]() |
![]() |
![]() |