References
Related links

Minischeme interpreter 
(if A B C)
(if TEST THEN ELSE)where
TEST
is an expression which returns a true or
false value (like a test (< x 1)
or (equal? A "Hello")
).
For example,
>> (if (< 1 2) 7 12) 7 >> (if (< 10 2) 7 12) 12 >> (if (equal? "hi" "Hi") "apple" "banana") banana >> (if (equal? "hi" "hi") "apple" "banana") apple >> (if (equal? "hi" 'hi) "apple" "banana") banana
(define win (window "choice demo")) (define CHaction (action (lambda (e) (if (equal? (readstring CH) "Hello") (writeexpr T "English")) (if (equal? (readstring CH) "Bon Jour") (writeexpr T "French")) (if (equal? (readstring CH) "Gutten Tag") (writeexpr T "German")) (if (equal? (readstring CH) "Konichiwa") (writeexpr T "Japanese")) (if (equal? (readstring CH) "Hola") (writeexpr T "Spanish")) ))) (define CH (choice "Hello" "Bon Jour" "Gutten Tag" "Konichiwa" "Hola" CHaction)) (define T (textfield "" 20)) (.add win (col (label "Choice demo") CH T)) (.pack win) (.show win)
The program needs to use readString
because (read CH)
will try
to read the string as a scheme term. So for Bon Jour, it will just read the Bon, and
for Gutten Tag it will just read the Gutten.
f
whose definition contains
another call to f
, this is called textual recursion.
(define win (window "Recursion Demo" (CourierBold 40))) ;; create a window (.resize win 200 200) ;; resize it (define T (textfield "" 10)) ;; create a textfield (.add win T) ;; add it to the window (.pack win) ;; pack the window (.show win) ;; make it appear on the screen (define (f x) ;; add the definition of f to the environment (Thread.sleep 1000L) (writeexpr T x) (if (< x 1) "done" (f ( x 1)))) (f 3) ;; start evolving the expression (f 3)Lets now trace through evolution of this program
(f 3)
==> (define win (window "Recursion Demo" (CourierBold 40))) create a window ==> (.resize win 200 200) resize it ==> (define T (textfield "" 10)) create a textfield ==> (.add win T) add it to the window ==> (.pack win) pack the window ==> (.show win) make it appear on the screen ==> (define (f x) (Thread.sleep 1000L) (writeexpr T x) (if (< x 1) "done" (f ( x 1)))) define the procedure f ==> (f 3) start evaluating (f 3) ==> (Thread.sleep 1000L) (writeexpr T 3) (if (< 3 1) "done" (f ( 3 1))) here it sleeps for 1 second ==> (writeexpr T 3) (if (< 3 1) "done" (f ( 3 1))) here it writes 3 on the textfield T ==> (if (< 3 1) "done" (f ( 3 1))) ==> (if #f "done" (f ( 3 1)) ==> (f ( 3 1)) ==> (f 2) ==> (Thread.sleep 1000L) (writeexpr T 2) (if (< 2 1) "done" (f ( 2 1))) sleep for a second ==> (writeexpr T 2) (if (< 2 1) "done" (f ( 2 1))) write 2 on textfield T ==> (if (< 2 1) "done" (f ( 2 1))) ==> (if #f "done" (f ( 2 1)) ==> (f ( 2 1)) ==> (f 1) ==> (Thread.sleep 1000L) (writeexpr T 1) (if (< 1 1) "done" (f ( 1 1))) sleep for 1 second ==> (writeexpr T 1) (if (< 1 1) "done" (f ( 1 1))) write 1 on textfield T ==> (if (< 1 1) "done" (f ( 1 1))) ==> (if #f "done" (f ( 1 1)) ==> (f ( 1 1)) ==> (f 0) ==> (Thread.sleep 1000L) (writeexpr T 0) (if (< 0 1) "done" (f ( 0 1))) sleep for 1 second ==> (writeexpr T 0) (if (< 0 1) "done" (f ( 0 1))) write 0 on textfield T ==> (if (< 0 1) "done" (f ( 0 1))) ==> (if #t "done" (f ( 0 1)) ==> "done"
(F a1 a2 ... an)to a user defined procedure
F
with
a definition
(define (F x1 ... xn) BODY)by replacing the call with the
BODY
,
but where the variables
x1, ..., xn
have been replaced with
the arguments
a1,...,an
to the call.
Some examples will make this clear.
(define (countdown n) (if (= n 0) 'done (countdown ( n 1))))Tracing through the evaluation of the expression
(countdown 3)
we see that the call (countdown 3)
gets transformed into
the calls (countdown 2)
,
(countdown 1)
, and finally
(countdown 0)
, which is transformed to the quoted
symbol 'done
, and the evaluation stops as quoted symbols
can not be further evaluated.
(countdown 3) (if (= 3 0) 'done (countdown ( 3 1))) (if false 'done (countdown ( 3 1))) (countdown ( 3 1)) (countdown 2) (if (= 2 0) 'done (countdown ( 2 1))) (if false 'done (countdown ( 2 1))) (countdown ( 2 1)) (countdown 1) (if (= 1 0) 'done (countdown ( 1 1))) (if false 'done (countdown ( 1 1))) (countdown ( 1 1)) (countdown 0) (if (= 0 0) 'done (countdown ( 0 1))) 'done
(define T (textfield "" 20 (HelveticaBold 24))) (define win (window "countdown" (col T))) (.pack win) (.show win) (define (sleep N) (Thread.sleep (.longValue (Math.round (* 1000.0 N))))) (define (visualcountdown n) (writeexpr T n) (sleep 0.33) (if (= n 0) 'done (visualcountdown ( n 1)))) (visualcountdown 10)You should try running this applet in the Scheme interpreter below: When we trace this new procedure the body contains three items which are grouped together and we must evaluate them from left to right, returning the result of the last expression. We have indicated this by enclosing the body in an expression of the form
(begin E1 E2 ... En)Using this convention we can now trace the visual counter program.
(visualcounter 3) (begin (writeexpr T 3) (sleep 1000) (if (= 3 0) 'done (visualcounter ( 3 1)))) (begin (sleep 1000) (if (= 3 0) 'done (visualcounter ( 3 1)))) (begin (if (= 3 0) 'done (visualcounter ( 3 1)))) (if (= 3 0) 'done (visualcounter ( 3 1))) (if false 'done (visualcounter ( 3 1))) (visualcounter ( 3 1)) (visualcounter 2) (begin (writeexpr T 2) (sleep 1000) (if (= 2 0) 'done (visualcounter ( 2 1)))) (begin (sleep 1000) (if (= 2 0) 'done (visualcounter ( 2 1)))) (begin (if (= 2 0) 'done (visualcounter ( 2 1)))) (if (= 2 0) 'done (visualcounter ( 2 1))) (if false 'done (visualcounter ( 2 1)))) (visualcounter ( 2 1)) (visualcounter 1) (begin (writeexpr T 1) (sleep 1000) (if (= 1 0) 'done (visualcounter ( 1 1)))) (begin (sleep 1000) (if (= 1 0) 'done (visualcounter ( 1 1)))) (begin (if (= 1 0) 'done (visualcounter ( 1 1)))) (if (= 1 0) 'done (visualcounter ( 1 1))) (if false 'done (visualcounter ( 1 1))) (visualcounter ( 1 1)) (visualcounter 0) (begin (writeexpr T 0) (sleep 1000) (if (= 0 0) 'done (visualcounter ( 0 1)))) (begin (sleep 1000) (if (= 0 0) 'done (visualcounter ( 0 1)))) (begin (if (= 0 0) 'done (visualcounter ( 0 1)))) (if (= 0 0) 'done (visualcounter ( 0 1))) 'doneThe counter procedure can also be modified to create a turtle that takes N random steps on a graphical canvase.
(define TA (textarea 10 20 (HelveticaBold 24))) (define win (window "countdown" (col TA))) (.pack win) (.show win) (define (sleep N) (Thread.sleep (.longValue (Math.round (* 1000.0 N))))) (define (sumton n s) (writeexpr TA (stringappend (readstring TA) "\n" (list 'sumton n s))) (sleep 1.0) (if (= n 0) 'done (sumton ( n 1) (+ s n)))) (sumton 10 0)Each time through the countdown loop, this procedure does the following:
Since the intermediate results are shown in the textfield the user can watch the sum accumulate.
p
.
(define (p n Subtotal) (if (= n 0) Subtotal (p ( n 1) (+ n Subtotal)))) ;; make the GUI (define X (textfield "100" 10)) (define T (label "0" 10)) (define B (button "sum numbers from 1 to n" (action (lambda(e) (writeexpr T "") (writeexpr T (p (readexpr X) 0)))))) (define win (window "test" (HelveticaPlain 18) (tablebyrow 2 (label "n") X B (label "") (label "sum:") T))) (.pack win) (.show win)It is interesting to trace through this new procedure for a simple call:
(p 5 0) (if (= 5 0) 0 (p ( 5 1) (+ 5 0))) (if false 0 (p ( 5 1) (+ 5 0))) (p ( 5 1) (+ 5 0)) (p 4 5) (if (= 4 0) 5 (p ( 4 1) (+ 4 5))) (if false 5 (p ( 4 1) (+ 4 5))) (p ( 4 1) (+ 4 5)) (p 3 9) (if (= 3 0) 9 (p ( 3 1) (+ 3 9))) (if false 9 (p ( 3 1) (+ 3 9))) (p ( 3 1) (+ 3 9)) (p 2 12) (if (= 2 0) 12 (p ( 2 1) (+ 2 12))) (if false 12 (p ( 2 1) (+ 2 12))) (p ( 2 1) (+ 2 12)) (p 1 14) (if (= 1 0) 14 (p ( 1 1) (+ 1 14))) (if false 14 (p ( 1 1) (+ 1 14))) (p ( 1 1) (+ 1 14)) (p 0 15) (if (= 0 0) 15 (p ( 0 1) (+ 0 15))) (if true 15 (p ( 0 1) (+ 0 15))) 15
(p a b)
is transformed into
(p ( a 1) (+ a b))
provided a
is not equal to zero.
When a=0
, then it is transformed into b
, which
is the final result. Thus, we can trace through the call (p 10 0)
by doing the indented "if" evaluation steps in our head, and we get:
(p 10 0) (p 9 10) (p 8 19) (p 7 27) (p 6 34) (p 5 40) (p 4 45) (p 3 49) (p 2 52) (p 1 54) (p 0 55) 55and indeed,
55 = 10+9+8+7+6+5+4+3+2+1
. Thus a call of
(writeexpr T (p (readexpr X) 0))would sum the numbers from 1 to whatever is in X and write the answer on T.
(define (power x n) (if (= n 0) 1 (* x (power x ( n 1)))))As we can see in the trace below (where we have performed the evaluation of the "if" expression in our heads"), each successive call creates a larger expression to evaluate until n = 0. After this point, we have a large expression which is evaluated from the outside in. It is not hard to see that this method will require about 2n steps to raise a number x to the power n.
(power 2 6) (* 2 (power 2 5)) (* 2 (* 2 (power 2 4))) (* 2 (* 2 (* 2 (power 2 3)))) (* 2 (* 2 (* 2 (* 2 (power 2 2))))) (* 2 (* 2 (* 2 (* 2 (* 2 (power 2 1)))))) (* 2 (* 2 (* 2 (* 2 (* 2 (* 2 (power 2 0))))))) (* 2 (* 2 (* 2 (* 2 (* 2 (* 2 1 )))))) (* 2 (* 2 (* 2 (* 2 (* 2 2 ))))) (* 2 (* 2 (* 2 (* 2 4 )))) (* 2 (* 2 (* 2 8 ))) (* 2 (* 2 16 )) (* 2 32 ) 64
x^{N} = (x^{N/2}) ^{2} (N even) x^{N} = x* (x^{(N1)/2})^{2} (N odd)The code for this procedure is as follows:
(define (sq x) (* x x)) (define (expt x n) (if (= n 0) 1.0 (if (even? n) (sq (expt x (/ n 2))) (* x (sq (expt x (/ ( n 1) 2)))))))Tracing through this procedure for the case of raising 2 to the 6th we don't see much advantage. Indeed, it seems significantly more complex.
(expt 2 6) (sq (expt 2 3)) (sq (* 2 (sq (expt 2 1)))) (sq (* 2 (sq (* 2 (expt 2 0))))) (sq (* 2 (sq (* 2 1.0)))) (sq (* 2 (sq 2.0))) (sq (* 2 4.0)) (sq 8.0) 64.0But the benefit of this approach comes when we try to raise 2 to the 33th power:
(expt 2 33) (* 2 (expt 2 32)) (* 2 (sq (expt 2 16))) (* 2 (sq (sq (expt 2 8)))) (* 2 (sq (sq (sq (expt 2 4))))) (* 2 (sq (sq (sq (sq (expt 2 2)))))) (* 2 (sq (sq (sq (sq (sq (expt 2 1))))))) (* 2 (sq (sq (sq (sq (sq (* 2 (expt 2 0)))))))) (* 2 (sq (sq (sq (sq (sq (* 2 1.0))))))) (* 2 (sq (sq (sq (sq (sq 2.0)))))) (* 2 (sq (sq (sq (sq 4.0))))) (* 2 (sq (sq (sq 16.0)))) (* 2 (sq (sq 256.0))) (* 2 (sq 65536.0)) (* 2 4294967296.0) 8589934592.0This procedure accomplishes in 14 steps what would require 66 steps for the
power
procedure. Observe that
for each successive call of the expt procedure the argument
is halved. Indeed, the number of steps required by
the (expt x n) procedure is exactly twice the length
of the number n when written as a binary number.
T = (modulo N^{E} M)Similarly, we decode T to get back our original message N by raising it the E' power and taking the remainder upon division by M:
N = (modulo T^{E'} M)where (E',M) is the private key.
The point here is that M and E are typically very large numbers, possibly hundreds of decimal digits long,
and the simple power
procedure would run for billions of years without finishing. However,
the clever exponentiation algorithm can be modified to compute (modulo N^{E} M)
in at most
2K steps where K is the lenght of N as a binary number, typically around 1000. The modified version
is called exptmod and is written below:
(import "java.math.BigInteger") ;; need to use BigInteger's (define (exptmoddemo x n m) (define (sq x) (.multiply x x)) (define zero (BigInteger. "0")) (define one (BigInteger. "1")) (define two (BigInteger. "2")) (define (even? n) (= (.mod n two) 0)) (define (exptmod x n m) (.mod (if (.equals n zero) one (if (even? n) (sq (exptmod x (.divide n two) m)) (.multiply x (sq (exptmod x (.divide (.subtract n one) two) m))))) m)) (exptmod (BigInteger. x) (BigInteger. n) (BigInteger. m)) ) (exptmoddemo "12321" "1234567890123456789901234567" "9876543210987654321")Here we use mult and div instead of * and /, because we need to use special procedures (available in Java) for computing with very large numbers. As a final example, we show how to compute the remainder of (3 raised to the 33 power) when divided by 100. (Note: to save space we have abbreviated
modulo
to m
in the following trace.)
(exptmod 3 17 100) (m (* 3 (sq (exptmod 3 8)))) 100) (m (* 3 (sq (m (sq (exptmod 3 4))) 100))) 100) (m (* 3 (sq (m (sq (m (sq (exptmod 3 2)) 100)) 100))) 100) (m (* 3 (sq (m (sq (m (sq (m (sq (exptmod 3 1)) 100)) 100)) 100))) 100) (m (* 3 (sq (m (sq (m (sq (m (sq (m (* 3 (sq (exptmod 3 0))) 100 )) 100)) 100)) 100))) 100) (m (* 3 (sq (m (sq (m (sq (m (sq (m (* 3 (sq 1 )) 100 )) 100)) 100)) 100))) 100) (m (* 3 (sq (m (sq (m (sq (m (sq 3 ) 100)) 100)) 100))) 100) (m (* 3 (sq (m (sq (m (sq 9 ) 100)) 100))) 100) (m (* 3 (sq (m (sq 81 ) 100))) 100) (m (* 3 (sq (m 6461 100))) 100) (m (* 3 (sq 61 ) 100) (m 11163 100) 63The basic algorithm is to either square or square and multiply by 3 and then to take the remainder. This is iterate once for each binary digit of the exponent E.