streams.scm 7.3 KB

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