streams.scm 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. ;;;; streams.scm --- general lazy streams
  2. ;;;; -*- Scheme -*-
  3. ;;;; Copyright (C) 1999, 2001, 2004, 2006, 2015 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. #:use-module ((srfi srfi-41) #:prefix srfi-41:)
  23. #:export (make-stream
  24. vector->stream port->stream
  25. stream->reversed-list
  26. stream->list&length stream->reversed-list&length
  27. stream->vector
  28. stream-fold)
  29. #:re-export ((srfi-41:stream-car . stream-car)
  30. (srfi-41:stream-cdr . stream-cdr)
  31. (srfi-41:stream-null? . stream-null?)
  32. (srfi-41:list->stream . list->stream)
  33. (srfi-41:stream->list . stream->list)
  34. (srfi-41:stream-for-each . stream-for-each)
  35. (srfi-41:stream-map . stream-map)))
  36. ;; Use:
  37. ;;
  38. ;; (make-stream producer initial-state)
  39. ;; - PRODUCER is a function of one argument, the current state.
  40. ;; it should return either a pair or an atom (i.e. anything that
  41. ;; is not a pair). if PRODUCER returns a pair, then the car of the pair
  42. ;; is the stream's head value, and the cdr is the state to be fed
  43. ;; to PRODUCER later. if PRODUCER returns an atom, then the stream is
  44. ;; considered depleted.
  45. ;;
  46. ;; (stream-car stream)
  47. ;; (stream-cdr stream)
  48. ;; (stream-null? stream)
  49. ;; - yes.
  50. ;;
  51. ;; (list->stream list)
  52. ;; (vector->stream vector)
  53. ;; - make a stream with the same contents as LIST/VECTOR.
  54. ;;
  55. ;; (port->stream port read)
  56. ;; - makes a stream of values which are obtained by READing from PORT.
  57. ;;
  58. ;; (stream->list stream)
  59. ;; - returns a list with the same contents as STREAM.
  60. ;;
  61. ;; (stream->reversed-list stream)
  62. ;; - as above, except the contents are in reversed order.
  63. ;;
  64. ;; (stream->list&length stream)
  65. ;; (stream->reversed-list&length stream)
  66. ;; - multiple-valued versions of the above two, the second value is the
  67. ;; length of the resulting list (so you get it for free).
  68. ;;
  69. ;; (stream->vector stream)
  70. ;; - yes.
  71. ;;
  72. ;; (stream-fold proc init stream0 ...)
  73. ;; - PROC must take (+ 1 <number-of-stream-arguments>) arguments, like this:
  74. ;; (PROC car0 ... init). *NOTE*: the INIT argument is last, not first.
  75. ;; I don't have any preference either way, but it's consistent with
  76. ;; `fold[lr]' procedures from SRFI-1. PROC is applied to successive
  77. ;; elements of the given STREAM(s) and to the value of the previous
  78. ;; invocation (INIT on the first invocation). the last result from PROC
  79. ;; is returned.
  80. ;;
  81. ;; (stream-for-each proc stream0 ...)
  82. ;; - like `for-each' we all know and love.
  83. ;;
  84. ;; (stream-map proc stream0 ...)
  85. ;; - like `map', except returns a stream of results, and not a list.
  86. ;; Code:
  87. (define (make-stream m state)
  88. (srfi-41:stream-let recur ((state state))
  89. (let ((state (m state)))
  90. (if (pair? state)
  91. (srfi-41:stream-cons (car state) (recur (cdr state)))
  92. srfi-41:stream-null))))
  93. (define (vector->stream v)
  94. (make-stream
  95. (let ((len (vector-length v)))
  96. (lambda (i)
  97. (or (= i len)
  98. (cons (vector-ref v i) (+ 1 i)))))
  99. 0))
  100. (define (stream->reversed-list&length stream)
  101. (let loop ((s stream) (acc '()) (len 0))
  102. (if (srfi-41:stream-null? s)
  103. (values acc len)
  104. (loop (srfi-41:stream-cdr s)
  105. (cons (srfi-41:stream-car s) acc) (+ 1 len)))))
  106. (define (stream->reversed-list stream)
  107. (call-with-values
  108. (lambda () (stream->reversed-list&length stream))
  109. (lambda (l len) l)))
  110. (define (stream->list&length stream)
  111. (call-with-values
  112. (lambda () (stream->reversed-list&length stream))
  113. (lambda (l len) (values (reverse! l) len))))
  114. (define (stream->vector stream)
  115. (call-with-values
  116. (lambda () (stream->reversed-list&length stream))
  117. (lambda (l len)
  118. (let ((v (make-vector len)))
  119. (let loop ((i 0) (l l))
  120. (if (not (null? l))
  121. (begin
  122. (vector-set! v (- len i 1) (car l))
  123. (loop (+ 1 i) (cdr l)))))
  124. v))))
  125. (define (stream-fold f init stream . rest)
  126. (if (null? rest) ;fast path
  127. (stream-fold-one f init stream)
  128. (stream-fold-many f init (cons stream rest))))
  129. (define (stream-fold-one f r stream)
  130. (if (srfi-41:stream-null? stream)
  131. r
  132. (stream-fold-one f
  133. (f (srfi-41:stream-car stream) r)
  134. (srfi-41:stream-cdr stream))))
  135. (define (stream-fold-many f r streams)
  136. (if (or-map srfi-41:stream-null? streams)
  137. r
  138. (stream-fold-many f
  139. (apply f (let recur ((cars
  140. (map srfi-41:stream-car streams)))
  141. (if (null? cars)
  142. (list r)
  143. (cons (car cars)
  144. (recur (cdr cars))))))
  145. (map srfi-41:stream-cdr streams))))
  146. (define (port->stream port read)
  147. (make-stream (lambda (p)
  148. (let ((o (read p)))
  149. (or (eof-object? o)
  150. (cons o p))))
  151. port))
  152. ;;; streams.scm ends here