srfi-41.scm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. ;;; srfi-41.scm -- SRFI 41 streams
  2. ;; Copyright (c) 2007 Philip L. Bewig
  3. ;; Copyright (c) 2011, 2012, 2013 Free Software Foundation, Inc.
  4. ;; Permission is hereby granted, free of charge, to any person obtaining
  5. ;; a copy of this software and associated documentation files (the
  6. ;; "Software"), to deal in the Software without restriction, including
  7. ;; without limitation the rights to use, copy, modify, merge, publish,
  8. ;; distribute, sublicense, and/or sell copies of the Software, and to
  9. ;; permit persons to whom the Software is furnished to do so, subject to
  10. ;; the following conditions:
  11. ;;
  12. ;; The above copyright notice and this permission notice shall be
  13. ;; included in all copies or substantial portions of the Software.
  14. ;;
  15. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  17. ;; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
  18. ;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  19. ;; BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN
  20. ;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN
  21. ;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. ;; SOFTWARE.
  23. (define-module (srfi srfi-41)
  24. #:use-module (srfi srfi-1)
  25. #:use-module (srfi srfi-8)
  26. #:use-module (srfi srfi-9)
  27. #:use-module (srfi srfi-9 gnu)
  28. #:use-module (srfi srfi-26)
  29. #:use-module (ice-9 match)
  30. #:export (stream-null stream-cons stream? stream-null? stream-pair?
  31. stream-car stream-cdr stream-lambda define-stream
  32. list->stream port->stream stream stream->list stream-append
  33. stream-concat stream-constant stream-drop stream-drop-while
  34. stream-filter stream-fold stream-for-each stream-from
  35. stream-iterate stream-length stream-let stream-map
  36. stream-match stream-of stream-range stream-ref stream-reverse
  37. stream-scan stream-take stream-take-while stream-unfold
  38. stream-unfolds stream-zip))
  39. (cond-expand-provide (current-module) '(srfi-41))
  40. ;;; Private supporting functions and macros.
  41. (define-syntax-rule (must pred obj func msg args ...)
  42. (let ((item obj))
  43. (unless (pred item)
  44. (throw 'wrong-type-arg func msg (list args ...) (list item)))))
  45. (define-syntax-rule (must-not pred obj func msg args ...)
  46. (let ((item obj))
  47. (when (pred item)
  48. (throw 'wrong-type-arg func msg (list args ...) (list item)))))
  49. (define-syntax-rule (must-every pred objs func msg args ...)
  50. (let ((flunk (remove pred objs)))
  51. (unless (null? flunk)
  52. (throw 'wrong-type-arg func msg (list args ...) flunk))))
  53. (define-syntax-rule (first-value expr)
  54. (receive (first . _) expr
  55. first))
  56. (define-syntax-rule (second-value expr)
  57. (receive (first second . _) expr
  58. second))
  59. (define-syntax-rule (third-value expr)
  60. (receive (first second third . _) expr
  61. third))
  62. (define-syntax define-syntax*
  63. (syntax-rules ()
  64. ((_ (name . args) body ...)
  65. (define-syntax name (lambda* args body ...)))
  66. ((_ name syntax)
  67. (define-syntax name syntax))))
  68. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  69. ;;
  70. ;; Here we include a copy of the code of srfi-45.scm (but with renamed
  71. ;; identifiers), in order to create a new promise type that's disjoint
  72. ;; from the promises created by srfi-45. Ideally this should be done
  73. ;; using a 'make-promise-type' macro that instantiates a copy of this
  74. ;; code, but a psyntax bug in Guile 2.0 prevents this from working
  75. ;; properly: <http://bugs.gnu.org/13995>. So for now, we duplicate the
  76. ;; code.
  77. ;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
  78. ;; Copyright (C) 2003 André van Tonder. All Rights Reserved.
  79. ;; Permission is hereby granted, free of charge, to any person
  80. ;; obtaining a copy of this software and associated documentation
  81. ;; files (the "Software"), to deal in the Software without
  82. ;; restriction, including without limitation the rights to use, copy,
  83. ;; modify, merge, publish, distribute, sublicense, and/or sell copies
  84. ;; of the Software, and to permit persons to whom the Software is
  85. ;; furnished to do so, subject to the following conditions:
  86. ;; The above copyright notice and this permission notice shall be
  87. ;; included in all copies or substantial portions of the Software.
  88. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  89. ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  90. ;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  91. ;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  92. ;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  93. ;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  94. ;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  95. ;; SOFTWARE.
  96. (define-record-type stream-promise (make-stream-promise val) stream-promise?
  97. (val stream-promise-val stream-promise-val-set!))
  98. (define-record-type stream-value (make-stream-value tag proc) stream-value?
  99. (tag stream-value-tag stream-value-tag-set!)
  100. (proc stream-value-proc stream-value-proc-set!))
  101. (define-syntax-rule (stream-lazy exp)
  102. (make-stream-promise (make-stream-value 'lazy (lambda () exp))))
  103. (define (stream-eager x)
  104. (make-stream-promise (make-stream-value 'eager x)))
  105. (define-syntax-rule (stream-delay exp)
  106. (stream-lazy (stream-eager exp)))
  107. (define (stream-force promise)
  108. (let ((content (stream-promise-val promise)))
  109. (case (stream-value-tag content)
  110. ((eager) (stream-value-proc content))
  111. ((lazy) (let* ((promise* ((stream-value-proc content)))
  112. (content (stream-promise-val promise)))
  113. (if (not (eqv? (stream-value-tag content) 'eager))
  114. (begin (stream-value-tag-set! content
  115. (stream-value-tag (stream-promise-val promise*)))
  116. (stream-value-proc-set! content
  117. (stream-value-proc (stream-promise-val promise*)))
  118. (stream-promise-val-set! promise* content)))
  119. (stream-force promise))))))
  120. ;;
  121. ;; End of the copy of the code from srfi-45.scm
  122. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  123. ;;; Primitive stream functions and macros: (streams primitive)
  124. (define stream? stream-promise?)
  125. (define %stream-null (cons 'stream 'null))
  126. (define stream-null (stream-eager %stream-null))
  127. (define (stream-null? obj)
  128. (and (stream-promise? obj)
  129. (eqv? (stream-force obj) %stream-null)))
  130. (define-record-type stream-pare (make-stream-pare kar kdr) stream-pare?
  131. (kar stream-kar)
  132. (kdr stream-kdr))
  133. (define (stream-pair? obj)
  134. (and (stream-promise? obj) (stream-pare? (stream-force obj))))
  135. (define-syntax-rule (stream-cons obj strm)
  136. (stream-eager (make-stream-pare (stream-delay obj) (stream-lazy strm))))
  137. (define (stream-car strm)
  138. (must stream? strm 'stream-car "non-stream")
  139. (let ((pare (stream-force strm)))
  140. (must stream-pare? pare 'stream-car "null stream")
  141. (stream-force (stream-kar pare))))
  142. (define (stream-cdr strm)
  143. (must stream? strm 'stream-cdr "non-stream")
  144. (let ((pare (stream-force strm)))
  145. (must stream-pare? pare 'stream-cdr "null stream")
  146. (stream-kdr pare)))
  147. (define-syntax-rule (stream-lambda formals body0 body1 ...)
  148. (lambda formals (stream-lazy (begin body0 body1 ...))))
  149. (define* (stream-promise-visit promise #:key on-eager on-lazy)
  150. (define content (stream-promise-val promise))
  151. (case (stream-value-tag content)
  152. ((eager) (on-eager (stream-value-proc content)))
  153. ((lazy) (on-lazy (stream-value-proc content)))))
  154. (set-record-type-printer! stream-promise
  155. (lambda (strm port)
  156. (display "#<stream" port)
  157. (let loop ((strm strm))
  158. (stream-promise-visit strm
  159. #:on-eager (lambda (pare)
  160. (cond ((eq? pare %stream-null)
  161. (write-char #\> port))
  162. (else
  163. (write-char #\space port)
  164. (stream-promise-visit (stream-kar pare)
  165. #:on-eager (cut write <> port)
  166. #:on-lazy (lambda (_) (write-char #\? port)))
  167. (loop (stream-kdr pare)))))
  168. #:on-lazy (lambda (_) (display " ...>" port))))))
  169. ;;; Derived stream functions and macros: (streams derived)
  170. (define-syntax-rule (define-stream (name . formal) body0 body1 ...)
  171. (define name (stream-lambda formal body0 body1 ...)))
  172. (define-syntax-rule (stream-let tag ((name val) ...) body1 body2 ...)
  173. ((letrec ((tag (stream-lambda (name ...) body1 body2 ...))) tag) val ...))
  174. (define (list->stream objs)
  175. (define (list? x)
  176. (or (proper-list? x) (circular-list? x)))
  177. (must list? objs 'list->stream "non-list argument")
  178. (stream-let recur ((objs objs))
  179. (if (null? objs) stream-null
  180. (stream-cons (car objs) (recur (cdr objs))))))
  181. (define* (port->stream #:optional (port (current-input-port)))
  182. (must input-port? port 'port->stream "non-input-port argument")
  183. (stream-let recur ()
  184. (let ((c (read-char port)))
  185. (if (eof-object? c) stream-null
  186. (stream-cons c (recur))))))
  187. (define-syntax stream
  188. (syntax-rules ()
  189. ((_) stream-null)
  190. ((_ x y ...) (stream-cons x (stream y ...)))))
  191. ;; Common helper for the various eager-folding functions, such as
  192. ;; stream-fold, stream-drop, stream->list, stream-length, etc.
  193. (define-inlinable (stream-fold-aux proc base strm limit)
  194. (do ((val base (and proc (proc val (stream-car strm))))
  195. (strm strm (stream-cdr strm))
  196. (limit limit (and limit (1- limit))))
  197. ((or (and limit (zero? limit)) (stream-null? strm))
  198. (values val strm limit))))
  199. (define stream->list
  200. (case-lambda
  201. ((strm) (stream->list #f strm))
  202. ((n strm)
  203. (must stream? strm 'stream->list "non-stream argument")
  204. (when n
  205. (must integer? n 'stream->list "non-integer count")
  206. (must exact? n 'stream->list "inexact count")
  207. (must-not negative? n 'stream->list "negative count"))
  208. (reverse! (first-value (stream-fold-aux xcons '() strm n))))))
  209. (define (stream-append . strms)
  210. (must-every stream? strms 'stream-append "non-stream argument")
  211. (stream-let recur ((strms strms))
  212. (if (null? strms) stream-null
  213. (let ((strm (car strms)))
  214. (if (stream-null? strm) (recur (cdr strms))
  215. (stream-cons (stream-car strm)
  216. (recur (cons (stream-cdr strm) (cdr strms)))))))))
  217. (define (stream-concat strms)
  218. (must stream? strms 'stream-concat "non-stream argument")
  219. (stream-let recur ((strms strms))
  220. (if (stream-null? strms) stream-null
  221. (let ((strm (stream-car strms)))
  222. (must stream? strm 'stream-concat "non-stream object in input stream")
  223. (if (stream-null? strm) (recur (stream-cdr strms))
  224. (stream-cons (stream-car strm)
  225. (recur (stream-cons (stream-cdr strm)
  226. (stream-cdr strms)))))))))
  227. (define stream-constant
  228. (case-lambda
  229. (() stream-null)
  230. (objs (list->stream (apply circular-list objs)))))
  231. (define-syntax* (stream-do x)
  232. (define (end x)
  233. (syntax-case x ()
  234. (() #'(if #f #f))
  235. ((result) #'result)
  236. ((result ...) #'(begin result ...))))
  237. (define (var-step v s)
  238. (syntax-case s ()
  239. (() v)
  240. ((e) #'e)
  241. (_ (syntax-violation 'stream-do "bad step expression" x s))))
  242. (syntax-case x ()
  243. ((_ ((var init . step) ...)
  244. (test result ...)
  245. expr ...)
  246. (with-syntax ((result (end #'(result ...)))
  247. ((step ...) (map var-step #'(var ...) #'(step ...))))
  248. #'(stream-let loop ((var init) ...)
  249. (if test result
  250. (begin
  251. expr ...
  252. (loop step ...))))))))
  253. (define (stream-drop n strm)
  254. (must integer? n 'stream-drop "non-integer argument")
  255. (must exact? n 'stream-drop "inexact argument")
  256. (must-not negative? n 'stream-drop "negative argument")
  257. (must stream? strm 'stream-drop "non-stream argument")
  258. (second-value (stream-fold-aux #f #f strm n)))
  259. (define (stream-drop-while pred? strm)
  260. (must procedure? pred? 'stream-drop-while "non-procedural argument")
  261. (must stream? strm 'stream-drop-while "non-stream argument")
  262. (stream-do ((strm strm (stream-cdr strm)))
  263. ((or (stream-null? strm) (not (pred? (stream-car strm)))) strm)))
  264. (define (stream-filter pred? strm)
  265. (must procedure? pred? 'stream-filter "non-procedural argument")
  266. (must stream? strm 'stream-filter "non-stream argument")
  267. (stream-let recur ((strm strm))
  268. (cond ((stream-null? strm) stream-null)
  269. ((pred? (stream-car strm))
  270. (stream-cons (stream-car strm) (recur (stream-cdr strm))))
  271. (else (recur (stream-cdr strm))))))
  272. (define (stream-fold proc base strm)
  273. (must procedure? proc 'stream-fold "non-procedural argument")
  274. (must stream? strm 'stream-fold "non-stream argument")
  275. (first-value (stream-fold-aux proc base strm #f)))
  276. (define stream-for-each
  277. (case-lambda
  278. ((proc strm)
  279. (must procedure? proc 'stream-for-each "non-procedural argument")
  280. (must stream? strm 'stream-for-each "non-stream argument")
  281. (do ((strm strm (stream-cdr strm)))
  282. ((stream-null? strm))
  283. (proc (stream-car strm))))
  284. ((proc strm . rest)
  285. (let ((strms (cons strm rest)))
  286. (must procedure? proc 'stream-for-each "non-procedural argument")
  287. (must-every stream? strms 'stream-for-each "non-stream argument")
  288. (do ((strms strms (map stream-cdr strms)))
  289. ((any stream-null? strms))
  290. (apply proc (map stream-car strms)))))))
  291. (define* (stream-from first #:optional (step 1))
  292. (must number? first 'stream-from "non-numeric starting number")
  293. (must number? step 'stream-from "non-numeric step size")
  294. (stream-let recur ((first first))
  295. (stream-cons first (recur (+ first step)))))
  296. (define (stream-iterate proc base)
  297. (must procedure? proc 'stream-iterate "non-procedural argument")
  298. (stream-let recur ((base base))
  299. (stream-cons base (recur (proc base)))))
  300. (define (stream-length strm)
  301. (must stream? strm 'stream-length "non-stream argument")
  302. (- -1 (third-value (stream-fold-aux #f #f strm -1))))
  303. (define stream-map
  304. (case-lambda
  305. ((proc strm)
  306. (must procedure? proc 'stream-map "non-procedural argument")
  307. (must stream? strm 'stream-map "non-stream argument")
  308. (stream-let recur ((strm strm))
  309. (if (stream-null? strm) stream-null
  310. (stream-cons (proc (stream-car strm))
  311. (recur (stream-cdr strm))))))
  312. ((proc strm . rest)
  313. (let ((strms (cons strm rest)))
  314. (must procedure? proc 'stream-map "non-procedural argument")
  315. (must-every stream? strms 'stream-map "non-stream argument")
  316. (stream-let recur ((strms strms))
  317. (if (any stream-null? strms) stream-null
  318. (stream-cons (apply proc (map stream-car strms))
  319. (recur (map stream-cdr strms)))))))))
  320. (define-syntax* (stream-match x)
  321. (define (make-matcher x)
  322. (syntax-case x ()
  323. (() #'(? stream-null?))
  324. (rest (identifier? #'rest) #'rest)
  325. ((var . rest) (identifier? #'var)
  326. (with-syntax ((next (make-matcher #'rest)))
  327. #'(? (negate stream-null?)
  328. (= stream-car var)
  329. (= stream-cdr next))))))
  330. (define (make-guarded x fail)
  331. (syntax-case (list x fail) ()
  332. (((expr) _) #'expr)
  333. (((guard expr) fail) #'(if guard expr (fail)))))
  334. (syntax-case x ()
  335. ((_ strm-expr (pat . expr) ...)
  336. (with-syntax (((fail ...) (generate-temporaries #'(pat ...))))
  337. (with-syntax (((matcher ...) (map make-matcher #'(pat ...)))
  338. ((expr ...) (map make-guarded #'(expr ...) #'(fail ...))))
  339. #'(let ((strm strm-expr))
  340. (must stream? strm 'stream-match "non-stream argument")
  341. (match strm (matcher (=> fail) expr) ...)))))))
  342. (define-syntax-rule (stream-of expr rest ...)
  343. (stream-of-aux expr stream-null rest ...))
  344. (define-syntax stream-of-aux
  345. (syntax-rules (in is)
  346. ((_ expr base)
  347. (stream-cons expr base))
  348. ((_ expr base (var in stream) rest ...)
  349. (stream-let recur ((strm stream))
  350. (if (stream-null? strm) base
  351. (let ((var (stream-car strm)))
  352. (stream-of-aux expr (recur (stream-cdr strm)) rest ...)))))
  353. ((_ expr base (var is exp) rest ...)
  354. (let ((var exp)) (stream-of-aux expr base rest ...)))
  355. ((_ expr base pred? rest ...)
  356. (if pred? (stream-of-aux expr base rest ...) base))))
  357. (define* (stream-range first past #:optional step)
  358. (must number? first 'stream-range "non-numeric starting number")
  359. (must number? past 'stream-range "non-numeric ending number")
  360. (when step
  361. (must number? step 'stream-range "non-numeric step size"))
  362. (let* ((step (or step (if (< first past) 1 -1)))
  363. (lt? (if (< 0 step) < >)))
  364. (stream-let recur ((first first))
  365. (if (lt? first past)
  366. (stream-cons first (recur (+ first step)))
  367. stream-null))))
  368. (define (stream-ref strm n)
  369. (must stream? strm 'stream-ref "non-stream argument")
  370. (must integer? n 'stream-ref "non-integer argument")
  371. (must exact? n 'stream-ref "inexact argument")
  372. (must-not negative? n 'stream-ref "negative argument")
  373. (let ((res (stream-drop n strm)))
  374. (must-not stream-null? res 'stream-ref "beyond end of stream")
  375. (stream-car res)))
  376. (define (stream-reverse strm)
  377. (must stream? strm 'stream-reverse "non-stream argument")
  378. (stream-do ((strm strm (stream-cdr strm))
  379. (rev stream-null (stream-cons (stream-car strm) rev)))
  380. ((stream-null? strm) rev)))
  381. (define (stream-scan proc base strm)
  382. (must procedure? proc 'stream-scan "non-procedural argument")
  383. (must stream? strm 'stream-scan "non-stream argument")
  384. (stream-let recur ((base base) (strm strm))
  385. (if (stream-null? strm) (stream base)
  386. (stream-cons base (recur (proc base (stream-car strm))
  387. (stream-cdr strm))))))
  388. (define (stream-take n strm)
  389. (must stream? strm 'stream-take "non-stream argument")
  390. (must integer? n 'stream-take "non-integer argument")
  391. (must exact? n 'stream-take "inexact argument")
  392. (must-not negative? n 'stream-take "negative argument")
  393. (stream-let recur ((n n) (strm strm))
  394. (if (or (zero? n) (stream-null? strm)) stream-null
  395. (stream-cons (stream-car strm) (recur (1- n) (stream-cdr strm))))))
  396. (define (stream-take-while pred? strm)
  397. (must procedure? pred? 'stream-take-while "non-procedural argument")
  398. (must stream? strm 'stream-take-while "non-stream argument")
  399. (stream-let recur ((strm strm))
  400. (cond ((stream-null? strm) stream-null)
  401. ((pred? (stream-car strm))
  402. (stream-cons (stream-car strm) (recur (stream-cdr strm))))
  403. (else stream-null))))
  404. (define (stream-unfold mapper pred? generator base)
  405. (must procedure? mapper 'stream-unfold "non-procedural mapper")
  406. (must procedure? pred? 'stream-unfold "non-procedural pred?")
  407. (must procedure? generator 'stream-unfold "non-procedural generator")
  408. (stream-let recur ((base base))
  409. (if (pred? base)
  410. (stream-cons (mapper base) (recur (generator base)))
  411. stream-null)))
  412. (define (stream-unfolds gen seed)
  413. (define-stream (generator-stream seed)
  414. (receive (next . items) (gen seed)
  415. (stream-cons (list->vector items) (generator-stream next))))
  416. (define-stream (make-result-stream genstrm index)
  417. (define head (vector-ref (stream-car genstrm) index))
  418. (define-stream (tail) (make-result-stream (stream-cdr genstrm) index))
  419. (match head
  420. (() stream-null)
  421. (#f (tail))
  422. ((item) (stream-cons item (tail)))
  423. ((? list? items) (stream-append (list->stream items) (tail)))))
  424. (must procedure? gen 'stream-unfolds "non-procedural argument")
  425. (let ((genstrm (generator-stream seed)))
  426. (apply values (list-tabulate (vector-length (stream-car genstrm))
  427. (cut make-result-stream genstrm <>)))))
  428. (define (stream-zip strm . rest)
  429. (let ((strms (cons strm rest)))
  430. (must-every stream? strms 'stream-zip "non-stream argument")
  431. (stream-let recur ((strms strms))
  432. (if (any stream-null? strms) stream-null
  433. (stream-cons (map stream-car strms) (recur (map stream-cdr strms)))))))