timothy235

sicp-3-5-1-streams-are-delayed-lists

Mar 5th, 2017
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 7.49 KB | None | 0 0
  1. #lang racket
  2.  
  3. ;; Racket has built-in streams, but this is the book implementation.  Use
  4. ;; define-syntax-rule to create the new special forms my-delay and cons-stream.
  5.  
  6. ;; STREAMS
  7.  
  8. (define (memo-proc proc)
  9.   (define already-run? false)
  10.   (define result false)
  11.   (lambda ()
  12.     (cond [(not already-run?)
  13.            (set! result (proc))
  14.            (set! already-run? true)
  15.            result]
  16.           [else result])))
  17.  
  18. (define-syntax-rule (my-delay e) (memo-proc (lambda () e)))
  19. (define (my-force delayed-object) (delayed-object))
  20.  
  21. (define (stream-car s) (car s))
  22. (define (stream-cdr s) (my-force (cdr s)))
  23.  
  24. ;; Use this definition of cons-stream for memoized streams.
  25. (define-syntax-rule (cons-stream a b) (cons a (my-delay b)))
  26.  
  27. ;; ;; Use this definition of cons-stream for un-memoized streams.
  28. ;; (define-syntax-rule (no-memo-delay e) (lambda () e))
  29. ;; (define-syntax-rule (cons-stream a b) (cons a (no-memo-delay b)))
  30.  
  31. (define the-empty-stream empty)
  32. (define stream-null? empty?)
  33.  
  34. (define (my-stream-ref s n)
  35.   (if (zero? n)
  36.     (stream-car s)
  37.     (my-stream-ref (stream-cdr s) (sub1 n))))
  38.  
  39. (define (my-stream-map proc s)
  40.   (if (stream-null? s)
  41.     the-empty-stream
  42.     (cons-stream (proc (stream-car s))
  43.                  (my-stream-map proc (stream-cdr s)))))
  44.  
  45. (define (my-stream-filter pred s)
  46.   (cond [(stream-null? s) the-empty-stream]
  47.         [(pred (stream-car s))
  48.          (cons-stream (stream-car s)
  49.                       (my-stream-filter pred (stream-cdr s)))]
  50.         [else (my-stream-filter pred (stream-cdr s))]))
  51.  
  52. (define (my-stream-for-each proc s)
  53.   (cond [(stream-null? s) 'done]
  54.         [else (proc (stream-car s))
  55.               (my-stream-for-each proc (stream-cdr s))]))
  56.  
  57. (define (display-stream s) (my-stream-for-each displayln s))
  58.  
  59. (define (stream-enumerate-interval low high)
  60.   (if (> low high)
  61.     the-empty-stream
  62.     (cons-stream low
  63.                  (stream-enumerate-interval (add1 low) high))))
  64.  
  65. ;;;;;;;;;;
  66. ;; 3.50 ;;
  67. ;;;;;;;;;;
  68.  
  69. (define (my-generalized-stream-map proc . argstreams)
  70.   (if (stream-null? (car argstreams))
  71.     the-empty-stream
  72.     (cons-stream (apply proc (map stream-car argstreams))
  73.                  (apply my-generalized-stream-map
  74.                         (cons proc (map stream-cdr argstreams))))))
  75.  
  76. ;; TEST
  77.  
  78. (define s1 (stream-enumerate-interval 1 5))
  79. (define s2 (stream-enumerate-interval 11 15))
  80. (define t (my-generalized-stream-map + s1 s2))
  81. (my-stream-ref t 3)
  82. ;; 18
  83. (display-stream t)
  84. ;; 12
  85. ;; 14
  86. ;; 16
  87. ;; 18
  88. ;; 20
  89. ;; 'done
  90.  
  91. ;;;;;;;;;;
  92. ;; 3.51 ;;
  93. ;;;;;;;;;;
  94.  
  95. (define (show x)
  96.   (displayln x)
  97.   x)
  98.  
  99. (define x (my-stream-map show (stream-enumerate-interval 0 10)))
  100.  
  101. ;; WITH MEMOIZATION
  102.  
  103. (my-stream-ref x 5)
  104. ;; 0
  105. ;; 1
  106. ;; 2
  107. ;; 3
  108. ;; 4
  109. ;; 5
  110. ;; 5
  111.  
  112. (my-stream-ref x 7)
  113. ;; 6
  114. ;; 7
  115. ;; 7
  116.  
  117. ;; Suppose proc has a side-effect, like show does here.  How is this side-effect
  118. ;; expressed when we stream-map proc down a stream s?  What would be the
  119. ;; difference if we used un-memoized streams?
  120.  
  121. ;; Let t be (my-stream-map proc s).  When t is evaluated, the stream-car is
  122. ;; evaluated, but evaluation of the stream-cdr is delayed.  The stream-car of t is
  123. ;; proc of the stream-car of s.  This application of proc will produce a
  124. ;; side-effect.  But since a stream is stored as a pair consisting of a value and
  125. ;; a delayed expression, the stream-car will never again produce its side-effect
  126. ;; because that computation is never repeated.  (In effect the definition of
  127. ;; stream automatically caches the stream-car.)  This is true for both memoized
  128. ;; and un-memoized streams.
  129.  
  130. ;; For later stream elements, however, there is a difference.  With memoized
  131. ;; streams, later elements will only express their side-effect the first time they
  132. ;; are forced, simply because caching prevents the repetition of the computation
  133. ;; that produces the side-effect.  With un-memoized streams, however, the
  134. ;; side-effect will be repeated every time the later elements are forced.
  135.  
  136. ;; For example, repeating the above with un-memoized streams:
  137.  
  138. ;; ;; WITHOUT MEMOIZATION
  139.  
  140. ;; (my-stream-ref x 5)
  141. ;; ;; 0
  142. ;; ;; 1
  143. ;; ;; 2
  144. ;; ;; 3
  145. ;; ;; 4
  146. ;; ;; 5
  147. ;; ;; 5
  148.  
  149. ;; (my-stream-ref x 7)
  150. ;; ;; 1 ; notice there is no 0 this time
  151. ;; ;; 2
  152. ;; ;; 3
  153. ;; ;; 4
  154. ;; ;; 5
  155. ;; ;; 6
  156. ;; ;; 7
  157. ;; ;; 7
  158.  
  159. ;;;;;;;;;;
  160. ;; 3.52 ;;
  161. ;;;;;;;;;;
  162.  
  163. ;; WITH MEMOIZATION
  164.  
  165. (define sum 0)
  166. (define (accum x)
  167.   (set! sum (+ x sum))
  168.   sum)
  169.  
  170. (define seq (my-stream-map accum (stream-enumerate-interval 1 20)))
  171. sum ; sum 1
  172. ;; 1
  173.  
  174. (define y (my-stream-filter even? seq))
  175. sum ; sum 2
  176. ;; 6
  177.  
  178. (define z (my-stream-filter (lambda (x) (zero? (remainder x 5))) seq))
  179. sum ; sum 3
  180. ;; 10
  181.  
  182. (my-stream-ref y 7)
  183. ;; 136
  184. sum ; sum 4
  185. ;; 136
  186.  
  187. (display-stream z)
  188. ;; 10
  189. ;; 15
  190. ;; 45
  191. ;; 55
  192. ;; 105
  193. ;; 120
  194. ;; 190
  195. ;; 210
  196. ;; 'done
  197. sum ; sum 5
  198. ;; 210
  199.  
  200. ;; How are we getting these sums?
  201.  
  202. ;; seq is: 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 210
  203. ;; y is: 6 10 28 36 66 78 120 136 190 210
  204. ;; z is: 10 15 45 55 105 120 190 210
  205.  
  206. ;; Whenever a new element of seq is evaluated, accum has the side-effect of adding
  207. ;; its index to sum.
  208.  
  209. ;; At sum 1, seq is evaluated.  So its stream-car is evaluated.  So accum is
  210. ;; applied to 1.  Hence sum = sum + 1 = 0 + 1 = 1.
  211.  
  212. ;; At sum 2, y is evaluated.  So its stream-car is evaluated.  This means forcing
  213. ;; two more elements to get the first even element of seq.  So accum is applied to
  214. ;; 2 and 3.  Hence sum = sum + 2 + 3 = 1 + 2 + 3 = 6.
  215.  
  216. ;; At sum 3, z is evaluated.  So its stream-car is evaluated.  This means forcing
  217. ;; another element from seq, the fourth element, in order to get the first element
  218. ;; divisible by 5.  So accum is applied to 4.  Hence sum = sum + 4 = 6 + 4 = 10.
  219.  
  220. ;; At sum 4, (my-stream-ref y 7) evaluates the first eight elements of y, which
  221. ;; means evaluating the first 16 elements of seq (in order to get the first eight
  222. ;; even elements).  The first four of these sixteen elements have already been
  223. ;; forced, so accum gets applied to 5, 6, 7, up through 16.  Hence sum = sum + 5 +
  224. ;; 6 + 7 + ... + 16 = 10 + 5 + 6 + 7 + ... + 16 = 136.
  225.  
  226. ;; At sum 5, all of the elements of z are evaluated, which means all twenty
  227. ;; elements of seq get evaluated.  The first sixteen of those have already been
  228. ;; forced.  So accum gets applied to 17, 18, 19, and 20.  Hence sum = sum + 17 +
  229. ;; 18 + 19 + 20 = 136 + 17 + 18 + 19 + 20 = 210.
  230.  
  231. ;; How would this change for un-memoized streams?
  232.  
  233. ;; With un-memoized streams, stream elements repeat their side-effect every
  234. ;; time they are evaluated;  except for the stream-car, which only ever expresses
  235. ;; its side-effect once, as discussed in 3.51.
  236.  
  237. ;; Also note that seq is no longer deterministic, but its values will change
  238. ;; depending on how many times it has been invoked.  This is because invoking seq
  239. ;; calls accum, which increases sum, which in turn changes accum and seq.  This
  240. ;; means y and z will also change depending on how often seq has been invoked,
  241. ;; because they too depend on seq.  This complicates the answers we get below.
  242.  
  243. ;; ;; WITHOUT MEMOIZATION
  244.  
  245. ;; (define sum 0)
  246. ;; (define (accum x)
  247.   ;; (set! sum (+ x sum))
  248.   ;; sum)
  249.  
  250. ;; (define seq (my-stream-map accum (stream-enumerate-interval 1 20)))
  251. ;; sum
  252. ;; ;; 1
  253.  
  254. ;; (define y (my-stream-filter even? seq))
  255. ;; sum
  256. ;; ;; 6
  257.  
  258. ;; (define z (my-stream-filter (lambda (x) (zero? (remainder x 5))) seq))
  259. ;; sum
  260. ;; ;; 15
  261.  
  262. ;; (my-stream-ref y 7)
  263. ;; ;; 162
  264. ;; sum
  265. ;; ;; 162
  266.  
  267. ;; (display-stream z)
  268. ;; ;; 15
  269. ;; ;; 180
  270. ;; ;; 230
  271. ;; ;; 305
  272. ;; ;; 'done
  273. ;; sum
  274. ;; ;; 362
Add Comment
Please, Sign In to add comment