streams.scm 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. ;;;; streams.scm --- general lazy streams
  2. ;;;; -*- Scheme -*-
  3. ;;;; Copyright (C) 1999 Free Software Foundation, Inc.
  4. ;;;;
  5. ;;;; This program is free software; you can redistribute it and/or modify
  6. ;;;; it under the terms of the GNU General Public License as published by
  7. ;;;; the Free Software Foundation; either version 2, or (at your option)
  8. ;;;; any later version.
  9. ;;;;
  10. ;;;; This program is distributed in the hope that it will be useful,
  11. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;;;; GNU General Public License for more details.
  14. ;;;;
  15. ;;;; You should have received a copy of the GNU General Public License
  16. ;;;; along with this software; see the file COPYING. If not, write to
  17. ;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  18. ;;;; Boston, MA 02111-1307 USA
  19. ;; the basic stream operations are inspired by
  20. ;; (i.e. ripped off) Scheme48's `stream' package,
  21. ;; modulo stream-empty? -> stream-null? renaming.
  22. (define-module (ice-9 streams))
  23. (export make-stream
  24. stream-car stream-cdr stream-null?
  25. list->stream vector->stream port->stream
  26. stream->list stream->reversed-list
  27. stream->list&length stream->reversed-list&length
  28. stream->vector
  29. stream-fold stream-for-each stream-map)
  30. ;; Use:
  31. ;;
  32. ;; (make-stream producer initial-state)
  33. ;; - PRODUCER is a function of one argument, the current state.
  34. ;; it should return either a pair or an atom (i.e. anything that
  35. ;; is not a pair). if PRODUCER returns a pair, then the car of the pair
  36. ;; is the stream's head value, and the cdr is the state to be fed
  37. ;; to PRODUCER later. if PRODUCER returns an atom, then the stream is
  38. ;; considered depleted.
  39. ;;
  40. ;; (stream-car stream)
  41. ;; (stream-cdr stream)
  42. ;; (stream-null? stream)
  43. ;; - yes.
  44. ;;
  45. ;; (list->stream list)
  46. ;; (vector->stream vector)
  47. ;; - make a stream with the same contents as LIST/VECTOR.
  48. ;;
  49. ;; (port->stream port read)
  50. ;; - makes a stream of values which are obtained by READing from PORT.
  51. ;;
  52. ;; (stream->list stream)
  53. ;; - returns a list with the same contents as STREAM.
  54. ;;
  55. ;; (stream->reversed-list stream)
  56. ;; - as above, except the contents are in reversed order.
  57. ;;
  58. ;; (stream->list&length stream)
  59. ;; (stream->reversed-list&length stream)
  60. ;; - multiple-valued versions of the above two, the second value is the
  61. ;; length of the resulting list (so you get it for free).
  62. ;;
  63. ;; (stream->vector stream)
  64. ;; - yes.
  65. ;;
  66. ;; (stream-fold proc init stream0 ...)
  67. ;; - PROC must take (+ 1 <number-of-stream-arguments>) arguments, like this:
  68. ;; (PROC car0 ... init). *NOTE*: the INIT argument is last, not first.
  69. ;; I don't have any preference either way, but it's consistent with
  70. ;; `fold[lr]' procedures from SRFI-1. PROC is applied to successive
  71. ;; elements of the given STREAM(s) and to the value of the previous
  72. ;; invocation (INIT on the first invocation). the last result from PROC
  73. ;; is returned.
  74. ;;
  75. ;; (stream-for-each proc stream0 ...)
  76. ;; - like `for-each' we all know and love.
  77. ;;
  78. ;; (stream-map proc stream0 ...)
  79. ;; - like `map', except returns a stream of results, and not a list.
  80. ;; Code:
  81. (define (make-stream m state)
  82. (delay
  83. (let ((o (m state)))
  84. (if (pair? o)
  85. (cons (car o)
  86. (make-stream m (cdr o)))
  87. '()))))
  88. (define (stream-car stream)
  89. "Returns the first element in STREAM. This is equivalent to `car'."
  90. (car (force stream)))
  91. (define (stream-cdr stream)
  92. "Returns the first tail of STREAM. Equivalent to `(force (cdr STREAM))'."
  93. (cdr (force stream)))
  94. (define (stream-null? stream)
  95. "Returns `#t' if STREAM is the end-of-stream marker; otherwise
  96. returns `#f'. This is equivalent to `null?', but should be used
  97. whenever testing for the end of a stream."
  98. (null? (force stream)))
  99. (define (list->stream l)
  100. "Returns a newly allocated stream whose elements are the elements of
  101. LIST. Equivalent to `(apply stream LIST)'."
  102. (make-stream
  103. (lambda (l) l)
  104. l))
  105. (define (vector->stream v)
  106. (make-stream
  107. (let ((len (vector-length v)))
  108. (lambda (i)
  109. (or (= i len)
  110. (cons (vector-ref v i) (+ 1 i)))))
  111. 0))
  112. (define (stream->reversed-list&length stream)
  113. (let loop ((s stream) (acc '()) (len 0))
  114. (if (stream-null? s)
  115. (values acc len)
  116. (loop (stream-cdr s) (cons (stream-car s) acc) (+ 1 len)))))
  117. (define (stream->reversed-list stream)
  118. (call-with-values
  119. (lambda () (stream->reversed-list&length stream))
  120. (lambda (l len) l)))
  121. (define (stream->list&length stream)
  122. (call-with-values
  123. (lambda () (stream->reversed-list&length stream))
  124. (lambda (l len) (values (reverse! l) len))))
  125. (define (stream->list stream)
  126. "Returns a newly allocated list whose elements are the elements of STREAM.
  127. If STREAM has infinite length this procedure will not terminate."
  128. (reverse! (stream->reversed-list stream)))
  129. (define (stream->vector stream)
  130. (call-with-values
  131. (lambda () (stream->reversed-list&length stream))
  132. (lambda (l len)
  133. (let ((v (make-vector len)))
  134. (let loop ((i 0) (l l))
  135. (if (not (null? l))
  136. (begin
  137. (vector-set! v (- len i 1) (car l))
  138. (loop (+ 1 i) (cdr l)))))
  139. v))))
  140. (define (stream-fold f init stream . rest)
  141. (if (null? rest) ;fast path
  142. (stream-fold-one f init stream)
  143. (stream-fold-many f init (cons stream rest))))
  144. (define (stream-fold-one f r stream)
  145. (if (stream-null? stream)
  146. r
  147. (stream-fold-one f (f (stream-car stream) r) (stream-cdr stream))))
  148. (define (stream-fold-many f r streams)
  149. (if (or-map stream-null? streams)
  150. r
  151. (stream-fold-many f
  152. (apply f (let recur ((cars
  153. (map stream-car streams)))
  154. (if (null? cars)
  155. (list r)
  156. (cons (car cars)
  157. (recur (cdr cars))))))
  158. (map stream-cdr streams))))
  159. (define (stream-for-each f stream . rest)
  160. (if (null? rest) ;fast path
  161. (stream-for-each-one f stream)
  162. (stream-for-each-many f (cons stream rest))))
  163. (define (stream-for-each-one f stream)
  164. (if (not (stream-null? stream))
  165. (begin
  166. (f (stream-car stream))
  167. (stream-for-each-one f (stream-cdr stream)))))
  168. (define (stream-for-each-may f streams)
  169. (if (not (or-map stream-null? streams))
  170. (begin
  171. (apply f (map stream-car streams))
  172. (stream-for-each-one f (map stream-cdr streams)))))
  173. (define (stream-map f stream . rest)
  174. "Returns a newly allocated stream, each element being the result of
  175. invoking F with the corresponding elements of the STREAMs
  176. as its arguments."
  177. (if (null? rest) ;fast path
  178. (make-stream (lambda (s)
  179. (or (stream-null? s)
  180. (cons (f (stream-car s)) (stream-cdr s))))
  181. stream)
  182. (make-stream (lambda (streams)
  183. (or (or-map stream-null? streams)
  184. (cons (apply f (map stream-car streams))
  185. (map stream-cdr streams))))
  186. (cons stream rest))))
  187. (define (port->stream port read)
  188. (make-stream (lambda (p)
  189. (let ((o (read p)))
  190. (or (eof-object? o)
  191. (cons o p))))
  192. port))
  193. ;;; streams.scm ends here