Skip to content

Commit cfb57f8

Browse files
committed
Add implementation of stream
1 parent fb2675f commit cfb57f8

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed

chapter3/stream.rkt

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#lang racket
2+
3+
(provide (all-defined-out))
4+
(define (stream-null? s)
5+
(null? s))
6+
7+
(define the-empty-stream '())
8+
9+
(define-syntax cons-stream
10+
(syntax-rules ()
11+
[(cons-stream a b)
12+
(cons a (delay b))]))
13+
14+
(define (stream-car stream)
15+
(car stream))
16+
17+
(define (stream-cdr stream)
18+
(force (cdr stream)))
19+
20+
(define (memo-proc proc)
21+
(let ((already-run? false)
22+
(result false))
23+
(lambda ()
24+
(if (not already-run?)
25+
(begin (set! result (proc))
26+
(set! already-run? true)
27+
result)
28+
result))))
29+
30+
(define (force delayed-object)
31+
(delayed-object))
32+
33+
(define-syntax delay
34+
(syntax-rules ()
35+
[(delay expr) (memo-proc (lambda () expr))]))
36+
37+
(define (stream-ref s n)
38+
(if (= n 0)
39+
(stream-car s)
40+
(stream-ref (stream-cdr s) (- n 1))))
41+
42+
(define (stream-map proc s)
43+
(if (stream-null? s)
44+
the-empty-stream
45+
(cons-stream (proc (stream-car s))
46+
(stream-map proc (stream-cdr s)))))
47+
48+
(define (stream-for-each proc s)
49+
(if (stream-null? s)
50+
'done
51+
(begin (proc (stream-car s))
52+
(stream-for-each proc (stream-cdr s)))))
53+
54+
(define (display-stream s)
55+
(stream-for-each display-line s))
56+
57+
(define (display-line x)
58+
(newline)
59+
(display x))
60+
61+
(define (stream-filter pred stream)
62+
(cond ((stream-null? stream) the-empty-stream)
63+
((pred (stream-car stream))
64+
(cons-stream (stream-car stream)
65+
(stream-filter pred (stream-cdr stream))))
66+
(else (stream-filter pred (stream-cdr stream)))))
67+
68+
;; Testing utility functions
69+
(define (stream-to-list stream n)
70+
(if (or (= n 0)
71+
(stream-null? stream))
72+
'()
73+
(cons (stream-car stream)
74+
(stream-to-list (stream-cdr stream)
75+
(- n 1)))))
76+
(define (list-to-stream lst)
77+
(if (null? lst)
78+
the-empty-stream
79+
(cons-stream (car lst)
80+
(list-to-stream (cdr lst)))))
81+
(module+ test
82+
(require rackunit)
83+
84+
(test-case "Test for basic stream operation"
85+
(define s1 (cons-stream 1 (cons-stream 2 (cons-stream 3 the-empty-stream))))
86+
87+
(check-false (stream-null? s1))
88+
(check-true (stream-null? the-empty-stream))
89+
(check-equal? (stream-car s1) 1)
90+
(check-equal? (stream-car (stream-cdr s1)) 2)
91+
(check-equal? (stream-car (stream-cdr (stream-cdr s1))) 3)
92+
(check-true (stream-null? (stream-cdr (stream-cdr (stream-cdr s1)))))
93+
)
94+
95+
(test-case "Test for stream-ref"
96+
(define s1 (cons-stream 1 (cons-stream 2 (cons-stream 3 the-empty-stream))))
97+
(check-equal? (stream-ref s1 0) 1)
98+
(check-equal? (stream-ref s1 1) 2)
99+
(check-equal? (stream-ref s1 2) 3)
100+
)
101+
(test-case "Test for lazy-evaluation"
102+
(define eval-count 0)
103+
(define (expensive-computation x)
104+
(set! eval-count (+ eval-count 1))
105+
(* x x))
106+
(define lazy-stream
107+
(cons-stream 1
108+
(cons-stream (expensive-computation 2)
109+
(cons-stream (expensive-computation 3)
110+
the-empty-stream))))
111+
112+
;; no computation is called
113+
(check-equal? eval-count 0)
114+
115+
;; access first element, still no computation
116+
(check-equal? (stream-car lazy-stream) 1)
117+
(check-equal? eval-count 0)
118+
119+
;; access second element, first computation (triggered by
120+
;; stream-cdr)
121+
(check-equal? (stream-car (stream-cdr lazy-stream)) 4)
122+
(check-equal? eval-count 1)
123+
124+
;; access third element, second computation happens
125+
(check-equal? (stream-car (stream-cdr (stream-cdr lazy-stream))) 9)
126+
(check-equal? eval-count 2)
127+
)
128+
129+
(test-case "Test for memo-proc"
130+
(define memo-count 0)
131+
(define (counted-computation)
132+
(set! memo-count (+ memo-count 1))
133+
42)
134+
135+
(define memo-stream (cons-stream 1 (counted-computation)))
136+
137+
(stream-cdr memo-stream)
138+
(check-equal? memo-count 1)
139+
140+
;; won't eval the stream twice for the same proc
141+
(stream-cdr memo-stream)
142+
(check-equal? memo-count 1)
143+
)
144+
145+
(test-case "Test for stream-map"
146+
(define s3 (list-to-stream '(1 2 3 4 5)))
147+
(define squared (stream-map (lambda (x) (* x x)) s3))
148+
(check-equal? (stream-to-list squared 5) '(1 4 9 16 25))
149+
)
150+
151+
(test-case "Test for stream-filter"
152+
(define s3 (list-to-stream '(1 2 3 4 5)))
153+
(define even (stream-filter even? s3))
154+
(check-equal? (stream-to-list even 5) '(2 4))
155+
)
156+
157+
(test-case "Test for stream-for-each"
158+
(define results '())
159+
(define s (list-to-stream '(1 2 3 4 5)))
160+
(define result (stream-for-each
161+
(lambda (x)
162+
(set! results (cons x results)))
163+
s))
164+
(display-stream s)
165+
(check-equal? result 'done)
166+
(check-equal? results '(5 4 3 2 1))
167+
)
168+
)

0 commit comments

Comments
 (0)