196 lines
5.9 KiB
Scheme
196 lines
5.9 KiB
Scheme
(load "util.scm")
|
|
|
|
(display "\nex-3.9 - draw factorial evaluation model\n")
|
|
(display "[see comments]\n")
|
|
|
|
(define (factorial n)
|
|
(if (= n 1)
|
|
1
|
|
(* n (factorial (- n 1)))))
|
|
|
|
(define (factorial n)
|
|
(fact-iter 1 1 n))
|
|
(define (fact-iter product counter max-count)
|
|
(if (> counter max-count)
|
|
product
|
|
(fact-iter (* counter product)
|
|
(+ counter 1)
|
|
max-count)))
|
|
|
|
; Nothing to special. I drew this out in my 2020 notebook on page 203.
|
|
|
|
; The drawing in the Scheme-Wiki is nice too:
|
|
; http://community.schemewiki.org/?sicp-ex-3.9
|
|
|
|
; RECURSIVE VERSION
|
|
;
|
|
; global ________________________
|
|
; env | other var. |
|
|
; ------->| factorial : * |
|
|
; | | |
|
|
; |_____________|_________|
|
|
; | ^
|
|
; | |
|
|
; variables : n
|
|
; body: (if (= n 1) 1 (* n (factorial (- n 1))))
|
|
;
|
|
; (factorial 6)
|
|
;
|
|
; _______ ^
|
|
; E1 -->| n : 6 |___________| GLOBAL
|
|
; -------
|
|
; (* 6 (factorial 5))
|
|
; _______ ^
|
|
; E2 -->| n : 5 |___________| GLOBAL
|
|
; -------
|
|
; (* 5 (factorial 4))
|
|
; _______ ^
|
|
; E3 -->| n : 4 |___________| GLOBAL
|
|
; -------
|
|
; (* 4 (factorial 3))
|
|
; _______ ^
|
|
; E4 -->| n : 3 |___________| GLOBAL
|
|
; -------
|
|
; (* 3 (factorial 2))
|
|
; _______ ^
|
|
; E5 -->| n : 2 |___________| GLOBAL
|
|
; -------
|
|
; (* 2 (factorial 1))
|
|
; _______ ^
|
|
; E6 -->| n : 1 |___________| GLOBAL
|
|
; -------
|
|
; 1
|
|
;
|
|
; ITERATIVE VERSON
|
|
;
|
|
; global ___________________________________
|
|
; env | other var. |
|
|
; ------->| factorial : * |
|
|
; | fact-iter : | * |
|
|
; |_____________|_______________|____|
|
|
; | ^ | ^
|
|
; | | | |
|
|
; | | variable : (product counter max-count)
|
|
; | | body: (if (> counter max-count)
|
|
; | | prod
|
|
; | | (fact-iter (* counter product)
|
|
; | | (+ counter 1)
|
|
; | | max-count))
|
|
; | |
|
|
; variable: n
|
|
; body: (fact-iter 1 1 n)
|
|
;
|
|
; (factorial 6)
|
|
;
|
|
; _______ ^
|
|
; E1 -->| n : 6 |_____________| GLOBAL
|
|
; -------
|
|
; (fact-iter 1 1 n)
|
|
;
|
|
; E2 -->| product : 1 ^
|
|
; | counter : 1 ___| GLOBAL
|
|
; | max-count : 6
|
|
; (fact-iter 1 2 6)
|
|
;
|
|
; E3 -->| product : 1 ^
|
|
; | counter : 2 ____| GLOBAL
|
|
; | max-count : 6
|
|
; (fact-iter 2 3 6)
|
|
;
|
|
; E4 -->| product : 2 ^
|
|
; | counter : 3 _____| GLOBAL
|
|
; | max-count : 6
|
|
; (fact-iter 6 4 6)
|
|
;
|
|
; E5 -->| product : 6 ^
|
|
; | counter : 4 _____| GLOBAL
|
|
; | max-count : 6
|
|
; (fact-iter 24 5 6)
|
|
;
|
|
; E6 -->| product : 24 ^
|
|
; | counter : 5 _____| GLOBAL
|
|
; | max-count : 6
|
|
; (fact-iter 120 6 6)
|
|
;
|
|
; E7 -->| product : 120 ^
|
|
; | counter : 6 _____| GLOBAL
|
|
; | max-count : 6
|
|
; (fact-iter 720 7 6)
|
|
;
|
|
; E8 -->| product : 720 ^
|
|
; | counter : 7 _____| GLOBAL
|
|
; | max-count : 6
|
|
; 720
|
|
|
|
(display "\nex-3.10 - nested lambdas frames\n")
|
|
|
|
(define (make-withdraw initial-amount)
|
|
(let ((balance initial-amount))
|
|
(lambda (amount)
|
|
(display initial-amount) (newline)
|
|
(display balance) (newline)
|
|
(if (>= balance amount)
|
|
(begin (set! balance (- balance amount))
|
|
balance)
|
|
"Insufficient funds"))))
|
|
|
|
(define W1 (make-withdraw 100))
|
|
|
|
(W1 20)
|
|
(W1 20)
|
|
(W1 20)
|
|
|
|
; The let binding creates a second lambda procedure and consequently a
|
|
; second frame. We can use display to show that both initial-amount and balance
|
|
; are available via the first and second frame. However, only balance is
|
|
; affected by calls to the return procedure, as we can see.
|
|
|
|
; This is the ascii diagram from the Scheme community wiki:
|
|
|
|
; global->| make-withdraw : * |
|
|
; env. | W1 : * | |
|
|
; -------|---^-----|---^-
|
|
; | | | |
|
|
; | | parameter: initial-mount
|
|
; | | body: ((lambda (balance) ((...))) initial-mount)
|
|
; | |
|
|
; | _|___Frame_A__________
|
|
; | | initial-mount : 100 |<- E0
|
|
; | -^--------------------
|
|
; | |
|
|
; | _|__________Frame_B______
|
|
; | | balance : initial-mount | <- E1
|
|
; | -^-----------------------
|
|
; | |
|
|
; parameter: amount
|
|
; body: (if (>= balance amount) ... )
|
|
;
|
|
; (W1 50)
|
|
;
|
|
; Set! will affect Frame B, initial-mount remains unchanged in Frame A.
|
|
; _______________________
|
|
; global->| make-withdraw : * |
|
|
; env. | W1 : * | |
|
|
; -------|---^-----|---^-
|
|
; | | | |
|
|
; | | parameter: initial-mount
|
|
; | | body: ((lambda (balance) ((...))) initial-mount)
|
|
; | |
|
|
; | _|___Frame_A__________
|
|
; | | initial-mount : 100 |<- E0
|
|
; | -^--------------------
|
|
; | |
|
|
; | _|__________Frame_B___
|
|
; | | balance : 50 | <- E1
|
|
; | -^--------------------
|
|
; | |
|
|
; parameter: amount
|
|
; body: (if (>= balance amount) ... )
|
|
|
|
|
|
(display "\nex-3.11\n")
|
|
|
|
; Relatively clear to me what is going on. Let's move on.
|
|
(display "[see schemewiki]\n")
|
|
|