streams. solutions to exercise 3.51 and 3.52
authorRamakrishnan Muthukrishnan <vu3rdd@gmail.com>
Sun, 3 Jul 2011 06:31:11 +0000 (12:01 +0530)
committerRamakrishnan Muthukrishnan <vu3rdd@gmail.com>
Sun, 3 Jul 2011 06:31:11 +0000 (12:01 +0530)
src/sicp/ex3_51.rkt [new file with mode: 0644]
src/sicp/ex3_52.rkt [new file with mode: 0644]
src/sicp/streams.rkt [new file with mode: 0644]

diff --git a/src/sicp/ex3_51.rkt b/src/sicp/ex3_51.rkt
new file mode 100644 (file)
index 0000000..defdd8a
--- /dev/null
@@ -0,0 +1,130 @@
+#lang planet neil/sicp 
+
+(define (stream-car s) (car s))
+(define (stream-cdr s) (force (cdr s)))
+
+(define (stream-ref s n)
+  (if (= n 0)
+      (stream-car s)
+      (stream-ref (stream-cdr s)
+                  (- n 1))))
+
+(define (stream-map proc s)
+  (if (stream-null? s)
+      the-empty-stream
+      (cons-stream (proc (stream-car s))
+                   (stream-map proc (stream-cdr s)))))
+
+(define (stream-filter pred? s)
+  (cond [(stream-null? s) the-empty-stream]
+        [(pred? (stream-car s))
+         (cons-stream (stream-car s)
+                      (stream-filter pred? (stream-cdr s)))]
+        [else (stream-filter pred? (stream-cdr s))]))
+
+(define (stream-for-each proc s)
+  (if (stream-null? s)
+      'done
+      (begin
+        (proc (stream-car s))
+        (stream-for-each proc (stream-cdr s)))))
+
+(define (display-stream s)
+  (stream-for-each display-line s))
+
+(define (display-line x)
+  (newline)
+  (display x))
+
+;; stream-enumerate-interval
+(define (stream-enumerate-interval low high)
+  (if (> low high)
+      the-empty-stream
+      (cons-stream low
+                   (stream-enumerate-interval (+ low 1)
+                                              high))))
+
+#|
+
+(define (show x)
+  (display-line x)
+  x)
+
+(define x (stream-map show (stream-enumerate-interval 0 10)))
+
+This will display 0. The reason is that, we can reduce this expression
+to
+
+(cons
+     (show (car 
+                (cons 0 (delay (stream-enumerate-interval 1 10))))
+     (delay
+           (stream-map show (stream-cdr 
+                                       (cons 0 (delay (stream-enumerate-interval 1 10)))))))
+
+This will print 0 and the rest of the computation is delayed.
+
+(stream-ref x 5)
+
+stream-ref will keep calling stream-cdr on the stream for 5 times. This will 'force' evaluation
+of the delayed operations.
+
+x is (cons 0
+           (delay (stream-map show (stream-enumerate-interval 1 10))))
+
+Calling stream-cdr once, this expression becomes
+ (cons 0 
+       (cons-stream (show (stream-car (stream-enumerate-interval 1 10)))
+                    (stream-map show 
+                                (stream-cdr (stream-enumerate-interval 1 10)))))
+
+= 
+
+ (cons 0
+       (cons 1 ;; also prints 1
+             (delay (stream-map show 
+                                (stream-cdr (stream-enumerata-interval 1 10))))))
+
+As can be seen, this will print 1 and the rest are 'delayed'.
+
+Think of the output of (stream-enumerate-interval 0 10) as:
+
+(cons 0 
+      (delay (cons 1
+                   (delay (cons 2
+                                (delay (cons 3
+                                             (delay (cons 4
+                                                          .........
+                                                                   (delay (cons 10 the-empty-stream))...)
+
+Let us call it s.
+
+Now, x is (stream-map show s). This is equiv of:
+
+(cons (show (stream-car s))
+      (delay (stream-map show (stream-cdr s)))
+
+This will first print 0, when defined.
+
+(stream-ref 5 x) is equiv to:
+
+(stream-car (stream-cdr (stream-cdr (stream-cdr (stream-cdr (stream-cdr x))))))
+This will make the stream-map work on the 5 delayed computations and hence 
+numbers from 1 to 5 printed on the screen. Together will that, the value of
+(stream-ref s 5) == 5 will also be printed.
+
+> (stream-ref x 7)
+
+This will print 6 and 7 along with the value of the expression (i.e. 7).
+
+|#
+
+(define (show x)
+  (display-line x)
+  x)
+
+(define x (stream-map show (stream-enumerate-interval 0 10)))
+(stream-ref x 5)
+(stream-ref x 7)
+
diff --git a/src/sicp/ex3_52.rkt b/src/sicp/ex3_52.rkt
new file mode 100644 (file)
index 0000000..c7ec6ff
--- /dev/null
@@ -0,0 +1,191 @@
+#lang planet neil/sicp
+
+(define (stream-car s) (car s))
+(define (stream-cdr s) (force (cdr s)))
+
+(define (stream-ref s n)
+  (if (= n 0)
+      (stream-car s)
+      (stream-ref (stream-cdr s)
+                  (- n 1))))
+
+(define (stream-map proc s)
+  (if (stream-null? s)
+      the-empty-stream
+      (cons-stream (proc (stream-car s))
+                   (stream-map proc (stream-cdr s)))))
+
+(define (stream-filter pred? s)
+  (cond [(stream-null? s) the-empty-stream]
+        [(pred? (stream-car s))
+         (cons-stream (stream-car s)
+                      (stream-filter pred? (stream-cdr s)))]
+        [else (stream-filter pred? (stream-cdr s))]))
+
+(define (stream-for-each proc s)
+  (if (stream-null? s)
+      'done
+      (begin
+        (proc (stream-car s))
+        (stream-for-each proc (stream-cdr s)))))
+
+(define (display-stream s)
+  (stream-for-each display-line s))
+
+(define (display-line x)
+  (newline)
+  (display x))
+
+;; stream-enumerate-interval
+(define (stream-enumerate-interval low high)
+  (if (> low high)
+      the-empty-stream
+      (cons-stream low
+                   (stream-enumerate-interval (+ low 1)
+                                              high))))
+
+#|
+
+(define sum 0)
+(define (accum x)
+  (set! sum (+ x sum))
+  sum)
+
+(define seq (stream-map accum (stream-enumerate-interval 1 20)))
+
+(define y (stream-filter even? seq))
+
+(define z (stream-filter (lambda (x) (= (remainder x 5) 0))
+                         seq))
+
+(stream-ref y 7)
+
+(display-stream z)
+
+|#
+
+#|
+
+What is the value of sum after each of the above expressions is evaluated? 
+
+ANS:
+
+> (define seq (stream-map accum (stream-enumerate-interval 1 20)))
+1
+
+This is because (stream-enumerate-interval 1 20) builds up a stream
+which looks as follows:
+
+s ==
+
+(cons 1
+      (delay (cons 2
+                   (delay (cons 3
+                                (delay .......)))..))
+
+Now, calling stream-map will produce seq which looks like this:
+
+seq == (cons (accum (car s))  ;; adds (car s) to sum
+             (delay (stream-map accum (stream-cdr s))))
+    == (cons 1
+             (delay (stream-map accum (stream-cdr s))))
+|#
+
+#|
+
+(define y (stream-filter even? seq))
+
+This will first run (even? (stream-car seq)) which will be false for
+the first value (i.e. 1). So, it will do:
+
+(stream-filter even? (stream-cdr seq))
+
+Calling stream-cdr on the seq will 'force' the delayed computation.
+So, seq becomes:
+
+seq == (cons 1
+             (stream-map accum (stream-cdr s)))
+    == (cons 1
+             (cons (accum 2) ;; sum becomes 3
+                   (delay (stream-map accum (stream-cdr s)))))
+
+Now, stream-filter will be called with seq as:
+
+ (cons 3
+       (delay (stream-map accum (stream-cdr s))))
+
+Again, stream-filter will run the car of seq with the predicate:
+
+ (even? (car seq))
+
+which will be false; Now the new computation will be:
+
+ (cons (accum 3) ;; sum becomes 3 + 3 = 6
+       (delay (stream-map accum (stream-cdr s)))))
+
+When stream-filter runs the predicate, (even? (stream-car seq))
+it will return true. At this point, sum = 6.
+
+|#
+
+#|
+
+(define z (stream-filter (lambda (x) (= (remainder x 5) 0))
+                         seq))
+
+At this point, seq is
+
+(1 (3 (6 (delay (stream-map accum (stream-cdr s)))))
+
+The forming of the new value of z will run it thru 1, 3 and 6
+and finds that they are not multiple of 5. Now, seq is
+
+(cons (accum 4) ;; sum = 6 + 4 = 10
+      (delay (stream-map accum (stream-cdr s))))
+
+=
+(cons 10
+      (delay (stream-map accum (stream-cdr s)))))
+
+Now, stream-filter will run the predicate and will return
+true and returns a stream-cons. At this point, sum = 10.
+
+|#
+
+#|
+
+(stream-ref y 7)
+
+This will take out 7 values out of y, which means 7 even values. So,
+we produce 16 values in the initial stream before we get 7 even values.
+
+(cons 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 (delay (cons 17 (delay (cons 18 ...))))
+
+sum should be
+(+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)
+= 136
+
+|#
+
+#|
+
+(display-stream z)
+
+If we were to evaluate seq as a whole and also the rest, we would
+get the following.
+
+seq is:
+
+(1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 210)
+
+y is
+
+(10 28 36 66 78 120 136 190 210)
+
+z is
+
+(10 15 45 55 95 105 120 190 210) 
+
+sum is 210
+
+|#
\ No newline at end of file
diff --git a/src/sicp/streams.rkt b/src/sicp/streams.rkt
new file mode 100644 (file)
index 0000000..f7b2717
--- /dev/null
@@ -0,0 +1,61 @@
+#lang planet neil/sicp
+
+(define (stream-car s) (car s))
+(define (stream-cdr s) (force (cdr s)))
+
+(define (stream-ref s n)
+  (if (= n 0)
+      (stream-car s)
+      (stream-ref (stream-cdr s)
+                  (- n 1))))
+
+(define (stream-map proc s)
+  (if (stream-null? s)
+      the-empty-stream
+      (cons-stream (proc (stream-car s))
+                   (stream-map proc (stream-cdr s)))))
+
+(define (stream-filter pred? s)
+  (cond [(stream-null? s) the-empty-stream]
+        [(pred? (stream-car s))
+         (cons-stream (stream-car s)
+                      (stream-filter pred? (stream-cdr s)))]
+        [else (stream-filter pred? (stream-cdr s))]))
+
+(define (stream-for-each proc s)
+  (if (stream-null? s)
+      'done
+      (begin
+        (proc (stream-car s))
+        (stream-for-each proc (stream-cdr s)))))
+
+(define (display-stream s)
+  (stream-for-each display-line s))
+
+(define (display-line x)
+  (newline)
+  (display x))
+
+;; stream-enumerate-interval
+(define (stream-enumerate-interval low high)
+  (if (> low high)
+      the-empty-stream
+      (cons-stream low
+                   (stream-enumerate-interval (+ low 1)
+                                              high))))
+
+
+;; prime?
+(define (square x) (* x x))
+(define (smallest-divisor n)
+  (find-divisor n 2))
+(define (find-divisor n test-divisor)
+  (cond ((> (square test-divisor) n) n)
+        ((divides? test-divisor n) test-divisor)
+        (else (find-divisor n (+ test-divisor 1)))))
+(define (divides? a b)
+  (= (remainder b a) 0))
+
+(define (prime? n)
+  (= (smallest-divisor n) n))
+