diff --git a/doc/chibi.scrbl b/doc/chibi.scrbl index 684e2eff..9ee4aad2 100755 --- a/doc/chibi.scrbl +++ b/doc/chibi.scrbl @@ -1187,6 +1187,7 @@ snow-fort): \item{\hyperlink["http://srfi.schemers.org/srfi-33/srfi-33.html"]{(srfi 33) - bitwise operators}} \item{\hyperlink["http://srfi.schemers.org/srfi-38/srfi-38.html"]{(srfi 38) - read/write shared structures}} \item{\hyperlink["http://srfi.schemers.org/srfi-39/srfi-39.html"]{(srfi 39) - parameter objects}} +\item{\hyperlink["http://srfi.schemers.org/srfi-41/srfi-41.html"]{(srfi 41) - streams}} \item{\hyperlink["http://srfi.schemers.org/srfi-46/srfi-46.html"]{(srfi 46) - basic syntax-rules extensions}} \item{\hyperlink["http://srfi.schemers.org/srfi-55/srfi-55.html"]{(srfi 55) - require-extension}} \item{\hyperlink["http://srfi.schemers.org/srfi-62/srfi-62.html"]{(srfi 62) - s-expression comments}} diff --git a/lib/srfi/41.scm b/lib/srfi/41.scm new file mode 100644 index 00000000..6cba2443 --- /dev/null +++ b/lib/srfi/41.scm @@ -0,0 +1,359 @@ + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; primitive layer adapted from SRFI 41 reference impl +;; TODO: rewrite this in terms or R7RS lazy primitives + +(define-record-type Stream + (make-stream box) + stream? + (box stream-promise stream-promise!)) + +(define-record-type Stream-Pare + (make-stream-pare kar kdr) + stream-pare? + (kar stream-kar) + (kdr stream-kdr)) + +(define-syntax stream-lazy + (syntax-rules () + ((lazy expr) + (make-stream (cons 'lazy (lambda () expr)))))) + +(define (stream-eager expr) + (make-stream (cons 'eager expr))) + +(define-syntax stream-delay + (syntax-rules () + ((stream-delay expr) + (stream-lazy (stream-eager expr))))) + +(define (stream-force promise) + (let ((content (stream-promise promise))) + (case (car content) + ((eager) (cdr content)) + ((lazy) (let* ((promise* ((cdr content))) + (content (stream-promise promise))) + (if (not (eqv? (car content) 'eager)) + (begin (set-car! content (car (stream-promise promise*))) + (set-cdr! content (cdr (stream-promise promise*))) + (stream-promise! promise* content))) + (stream-force promise)))))) + +(define stream-null (stream-delay (cons 'stream 'null))) + +(define (stream-pair? obj) + (and (stream? obj) (stream-pare? (stream-force obj)))) + +(define (stream-null? obj) + (and (stream? obj) + (eqv? (stream-force obj) + (stream-force stream-null)))) + +(define-syntax stream-cons + (syntax-rules () + ((stream-cons obj strm) + (stream-delay (make-stream-pare (stream-delay obj) (stream-lazy strm)))))) + +(define (stream-car strm) + (cond ((not (stream? strm)) (error 'stream-car "non-stream")) + ((stream-null? strm) (error 'stream-car "null stream")) + (else (stream-force (stream-kar (stream-force strm)))))) + +(define (stream-cdr strm) + (cond ((not (stream? strm)) (error 'stream-cdr "non-stream")) + ((stream-null? strm) (error 'stream-cdr "null stream")) + (else (stream-kdr (stream-force strm))))) + +(define-syntax stream-lambda + (syntax-rules () + ((stream-lambda formals body0 body1 ...) + (lambda formals (stream-lazy (let () body0 body1 ...)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; derived + +(define-syntax assert + (syntax-rules () + ((assert expr ...) + (begin (unless expr (error "assertion failed" 'expr)) ...)))) + +(define-syntax define-stream + (syntax-rules () + ((define-stream (name . args) e0 e1 ...) + (define name + (stream-lambda args e0 e1 ...))))) + +(define-syntax stream-let + (syntax-rules () + ((stream-let lp ((name val) ...) e0 e1 ...) + ((letrec ((lp (stream-lambda (name ...) e0 e1 ...))) lp) + val ...)))) + +(define-syntax stream + (syntax-rules () + ((stream) stream-null) + ((stream x y ...) (stream-cons x (stream y ...))))) + +(define (list->stream ls) + (assert (list? ls)) + (let lp ((ls (reverse ls)) (res stream-null)) + (if (null? ls) + res + (lp (cdr ls) (stream-cons (car ls) res))))) + +(define (port->stream in) + (assert (input-port? in)) + (let lp () + (let ((ch (read-char in))) + (if (eof-object? ch) + stream-null + (stream-cons ch (lp)))))) + +(define (stream->list x . o) + (let ((n (if (pair? o) x +inf.0))) + (assert (not (negative? n))) + (let lp ((i 0) + (strm (if (pair? o) (car o) x)) + (res '())) + (if (or (>= i n) (stream-null? strm)) + (reverse res) + (lp (+ i 1) + (stream-cdr strm) + (cons (stream-car strm) res)))))) + +(define (stream-concat strms) + (assert (stream? strms)) + (if (stream-null? strms) + stream-null + (let lp ((strm (stream-car strms)) + (strms (stream-cdr strms))) + (assert (stream? strm)) + (cond + ((stream-null? strm) + (if (stream-null? strms) + stream-null + (lp (stream-car strms) (stream-cdr strms)))) + (else + (stream-cons (stream-car strm) + (lp (stream-cdr strm) strms))))))) + +(define (stream-append . strms) + (stream-concat (list->stream strms))) + +(define (stream-from n . o) + (let ((step (if (pair? o) (car o) 1))) + (assert (number? n) (number? step)) + (let lp ((n n)) + (stream-cons n (lp (+ n step)))))) + +(define (stream-range first past . o) + (let ((step (if (pair? o) (car o) (if (< first past) 1 -1)))) + (assert (number? first) (number? past) (number? step)) + (if (positive? step) + (stream-let lp ((n first)) + (if (< n past) + (stream-cons n (lp (+ n step))) + stream-null)) + (stream-let lp ((n first)) + (if (> n past) + (stream-cons n (lp (+ n step))) + stream-null))))) + +(define (stream-constant . o) + (let lp ((ls o)) + (if (null? ls) + (lp o) + (stream-cons (car ls) (lp (cdr ls)))))) + +(define (stream-ref strm k) + (assert (stream? strm) (integer? k) (not (negative? k))) + (if (positive? k) + (stream-ref (stream-cdr strm) (- k 1)) + (stream-car strm))) + +(define (stream-length strm) + (assert (stream? strm)) + (let lp ((strm strm) (len 0)) + (if (stream-null? strm) + len + (lp (stream-cdr strm) (+ len 1))))) + +(define (stream-drop k strm) + (assert (integer? k) (not (negative? k)) (stream? strm)) + (stream-let drop ((k k) (strm strm)) + (if (or (zero? k) (stream-null? strm)) + strm + (drop (- k 1) (stream-cdr strm))))) + +(define (stream-drop-while pred? strm) + (assert (procedure? pred?) (stream? strm)) + (stream-let drop-while ((strm strm)) + (if (or (stream-null? strm) (not (pred? (stream-car strm)))) + strm + (drop-while (stream-cdr strm))))) + +(define (stream-filter pred? strm) + (assert (procedure? pred?) (stream? strm)) + (stream-let filter ((strm strm)) + (cond ((stream-null? strm) stream-null) + ((pred? (stream-car strm)) + (stream-cons (stream-car strm) (filter (stream-cdr strm)))) + (else not (filter (stream-cdr strm)))))) + +(define (stream-for-each proc strm) + (assert (procedure? proc) (stream? strm)) + (when (stream-pair? strm) + (proc (stream-car strm)) + (stream-for-each proc (stream-cdr strm)))) + +(define (stream-fold kons knil strm) + (assert (procedure? kons) (stream? strm)) + (let fold ((acc knil) (strm strm)) + (if (stream-null? strm) + acc + (fold (kons (stream-car strm) acc) (stream-cdr strm))))) + +(define (stream-scan proc base strm) + (assert (procedure? proc) (stream? strm)) + (stream-let scan ((acc base) (strm strm)) + (if (stream-null? strm) + (stream acc) + (stream-cons acc + (scan (proc acc (stream-car strm)) + (stream-cdr strm)))))) + +(define (stream-map proc strm . o) + (assert (procedure? proc) (stream? strm)) + (if (pair? o) + (stream-let lp ((strms (cons strm o))) + (if (any stream-null? strms) + stream-null + (stream-cons (apply proc (map stream-car strms)) + (lp (map stream-cdr strms))))) + (stream-let lp ((strm strm)) + (if (stream-null? strm) + stream-null + (stream-cons (proc (stream-car strm)) + (lp (stream-cdr strm))))))) + +(define (stream-iterate proc base) + (assert (procedure? proc)) + (stream-let iterate ((base base)) + (stream-cons base (iterate (proc base))))) + +(define (stream-take k strm) + (assert (integer? k) (not (negative? k)) (stream? strm)) + (stream-let take ((k k) (strm strm)) + (if (and (positive? k) (stream-pair? strm)) + (stream-cons (stream-car strm) (take (- k 1) (stream-cdr strm))) + stream-null))) + +(define (stream-take-while pred strm) + (assert (procedure? pred) (stream? strm)) + (stream-let take-while ((strm strm)) + (if (and (stream-pair? strm) (pred (stream-car strm))) + (stream-cons (stream-car strm) (take-while (stream-cdr strm))) + stream-null))) + +(define-syntax stream-of + (syntax-rules () + ((stream-of expr . clauses) + (stream-of/aux expr stream-null . clauses)))) + +(define-syntax stream-of/aux + (syntax-rules (in is) + ((stream-of/aux expr tail) + (stream-cons expr tail)) + ((stream-of/aux expr tail (var in s) . rest) + (stream-let lp ((strm s)) + (if (stream-null? strm) + tail + (let ((var (stream-car strm))) + (stream-of/aux expr (lp (stream-cdr strm)) . rest))))) + ((stream-of/aux expr tail (var is e) . rest) + (let ((var e)) + (stream-of/aux expr tail . rest))) + ((stream-of/aux expr tail pred . rest) + (if pred (stream-of/aux expr tail . rest) tail)))) + +(define (stream-reverse strm) + (list->stream (reverse (stream->list strm)))) + +(define (stream-unfold mapper pred gen base) + (assert (procedure? mapper) (procedure? pred) (procedure? gen)) + (stream-let unfold ((base base)) + (if (pred base) + (stream-cons (mapper base) (unfold (gen base))) + stream-null))) + +(define (stream-unfolds proc seed) + (assert (procedure? proc)) + (let ((strm (stream-let lp ((seed seed)) + (call-with-values + (lambda () (proc seed)) + (lambda ls + (stream-cons (cdr ls) + (lp (car ls)))))))) + (apply values + (map (lambda (i) + (stream-let lp ((strm strm)) + (let ((x (list-ref (stream-car strm) i))) + (cond + ((null? x) stream-null) + ((pair? x) (stream-cons (car x) (lp (stream-cdr strm)))) + (else (lp (stream-cdr strm))))))) + (iota (length (stream-car strm))))))) + +(define (stream-zip strm . o) + (assert (stream? strm) (every stream? o)) + (stream-let lp ((strms (cons strm o))) + (if (every stream-pair? strms) + (stream-cons (map stream-car strms) + (lp (map stream-cdr strms))) + stream-null))) + +(define-syntax stream-match + (syntax-rules () + ((stream-match expr clause ...) + (let ((strm expr)) + (assert (stream? strm)) + (stream-match-next strm clause ...))))) + +(define-syntax stream-match-next + (syntax-rules () + ((stream-match-next strm) + (error "no pattern matched")) + ((stream-match-next strm clause . clauses) + (let ((fail (lambda () (stream-match-next strm . clauses)))) + (stream-match-one strm clause (fail)))))) + +(define-syntax stream-match-one + (syntax-rules (_) + ((stream-match-one strm (() . body) fail) + (if (stream-null? strm) + (stream-match-body fail . body) + fail)) + ((stream-match-one strm (_ . body) fail) + (stream-match-body fail . body)) + ((stream-match-one strm ((a . b) . body) fail) + (if (stream-pair? strm) + (stream-match-one + (stream-car strm) + (a + (stream-match-one (stream-cdr strm) (b . body) fail)) + fail) + fail)) + ((stream-match-one strm (a . body) fail) + (let ((a strm)) + (stream-match-body fail . body))))) + +(define-syntax stream-match-body + (syntax-rules () + ((stream-match-body fail fender expr) + (if fender expr fail)) + ((stream-match-body fail expr) + expr))) + +;; Local variables: +;; eval: (put 'stream-let 'scheme-indent-function 2) +;; End: diff --git a/lib/srfi/41.sld b/lib/srfi/41.sld new file mode 100644 index 00000000..09d3daad --- /dev/null +++ b/lib/srfi/41.sld @@ -0,0 +1,14 @@ + +(define-library (srfi 41) + (import (scheme base) (srfi 1)) + (export + stream-null stream-cons stream? stream-null? stream-pair? + stream-car stream-cdr stream-lambda) + (export + define-stream list->stream port->stream stream stream->list + stream-append stream-concat stream-constant stream-drop + stream-drop-while stream-filter stream-fold stream-for-each stream-from + stream-iterate stream-length stream-let stream-map stream-match _ + stream-of stream-range stream-ref stream-reverse stream-scan stream-take + stream-take-while stream-unfold stream-unfolds stream-zip) + (include "41.scm")) diff --git a/lib/srfi/41/test.sld b/lib/srfi/41/test.sld new file mode 100644 index 00000000..b2327880 --- /dev/null +++ b/lib/srfi/41/test.sld @@ -0,0 +1,359 @@ +;; Adapted for R7RS from original SRFI 41 r5rs.ss. + +;; Copyright (C) 2007 by Philip L. Bewig of Saint Louis, Missouri, +;; USA. All rights reserved. Permission is hereby granted, free of +;; charge, to any person obtaining a copy of this software and +;; associated documentation files (the "Software"), to deal in the +;; Software without restriction, including without limitation the +;; rights to use, copy, modify, merge, publish, distribute, +;; sublicense, and/or sell copies of the Software, and to permit +;; persons to whom the Software is furnished to do so, subject to the +;; following conditions: The above copyright notice and this +;; permission notice shall be included in all copies or substantial +;; portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", +;; WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +;; LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +;; PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +;; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +;; OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +;; OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; unit tests + +(define-library (srfi 41 test) + (import (scheme base) (srfi 41) (chibi test)) + (export run-tests) + (begin + + (define (add1 n) (+ n 1)) + (define strm123 (stream 1 2 3)) + (define (lsec proc . args) + (lambda x (apply proc (append args x)))) + (define (rsec proc . args) + (lambda x (apply proc (reverse (append (reverse args) (reverse x)))))) + (define nats + (stream-cons 0 (stream-map add1 nats))) + + ;; executing (run-tests) should produce no output + (define (run-tests) + + (test-begin "srfi-41: streams") + + ;; stream-null + (test #t (stream? stream-null)) + (test #t (stream-null? stream-null)) + (test #f (stream-pair? stream-null)) + + ;; stream-cons + (test #t (stream? (stream-cons 1 stream-null))) + (test #f (stream-null? (stream-cons 1 stream-null))) + (test #t (stream-pair? (stream-cons 1 stream-null))) + + ;; stream? + (test #t (stream? stream-null)) + (test #t (stream? (stream-cons 1 stream-null))) + (test #f (stream? "four")) + + ;; stream-null? + (test #t (stream-null? stream-null)) + (test #f (stream-null? (stream-cons 1 stream-null))) + (test #f (stream-null? "four")) + + ;; stream-pair? + (test #f (stream-pair? stream-null)) + (test #t (stream-pair? (stream-cons 1 stream-null))) + (test #f (stream-pair? "four")) + + ;; stream-car + (test-error (stream-car "four")) ; "stream-car: non-stream" + (test-error (stream-car stream-null)) ; "stream-car: null stream" + (test 1 (stream-car strm123)) + + ;; stream-cdr + (test-error (stream-cdr "four")) ; "stream-cdr: non-stream" + (test-error (stream-cdr stream-null)) ; "stream-cdr: null stream" + (test 2 (stream-car (stream-cdr strm123))) + + ;; stream-lambda + (test + '(2 4 6) + (stream->list + (letrec ((double + (stream-lambda (strm) + (if (stream-null? strm) + stream-null + (stream-cons + (* 2 (stream-car strm)) + (double (stream-cdr strm))))))) + (double strm123)))) + + ;; define-stream + (test + '(2 4 6) + (stream->list + (let () + (define-stream (double strm) + (if (stream-null? strm) + stream-null + (stream-cons + (* 2 (stream-car strm)) + (double (stream-cdr strm))))) + (double strm123)))) + + ;; list->stream + (test-error (list->stream "four")) ; "list->stream: non-list argument" + (test '() (stream->list (list->stream '()))) + (test '(1 2 3) (stream->list (list->stream '(1 2 3)))) + + ;; port->stream + (let* ((p (open-input-string "; Copyright 2007")) + (s (port->stream p))) + (test-error (port->stream "four")) + (test "; Copyright" (list->string (stream->list 11 s)) ) + (close-input-port p)) + + ;; stream + (test '() (stream->list (stream))) + (test '(1) (stream->list (stream 1))) + (test '(1 2 3) (stream->list (stream 1 2 3))) + + ;; stream->list + (test-error (stream->list '())) ; "stream->list: non-stream argument" + (test-error (stream->list "four" strm123)) ; "stream->list: non-integer count" + (test-error (stream->list -1 strm123)) ; "stream->list: negative count" + (test '() (stream->list (stream))) + (test '(1 2 3) (stream->list strm123)) + (test '(1 2 3) (stream->list 5 strm123)) + (test '(1 2 3) (stream->list 3 (stream-from 1))) + + ;; stream-append + (test-error (stream-append "four")) ; "stream-append: non-stream argument" + (test '(1 2 3) (stream->list (stream-append strm123))) + (test '(1 2 3 1 2 3) (stream->list (stream-append strm123 strm123))) + (test '(1 2 3 1 2 3 1 2 3) + (stream->list (stream-append strm123 strm123 strm123))) + (test '(1 2 3) (stream->list (stream-append strm123 stream-null))) + (test '(1 2 3) (stream->list (stream-append stream-null strm123))) + + ;; stream-concat + (test-error (stream-concat "four")) ; "stream-concat: non-stream argument" + (test '(1 2 3) (stream->list (stream-concat (stream strm123)))) + (test '(1 2 3 1 2 3) + (stream->list (stream-concat (stream strm123 strm123)))) + + ;; stream-constant + (test 1 (stream-ref (stream-constant 1) 100)) + (test 1 (stream-ref (stream-constant 1 2) 100)) + (test 1 (stream-ref (stream-constant 1 2 3) 3)) + + ;; stream-drop + (test-error (stream-drop "four" strm123)) ; "stream-drop: non-integer argument" + (test-error (stream-drop -1 strm123)) ; "stream-drop: negative argument" + (test-error (stream-drop 2 "four")) ; "stream-drop: non-stream argument" + (test '() (stream->list (stream-drop 0 stream-null))) + (test '(1 2 3) (stream->list (stream-drop 0 strm123))) + (test '(2 3) (stream->list (stream-drop 1 strm123))) + (test '() (stream->list (stream-drop 5 strm123))) + + ;; stream-drop-while + (test-error ; "stream-drop-while: non-procedural argument" + (stream-drop-while "four" strm123)) + (test-error ; "stream-drop-while: non-stream argument" + (stream-drop-while odd? "four")) + (test '() (stream->list (stream-drop-while odd? stream-null))) + (test '(2 3) (stream->list (stream-drop-while odd? strm123))) + (test '(1 2 3) (stream->list (stream-drop-while even? strm123))) + (test '() (stream->list (stream-drop-while positive? strm123))) + (test '(1 2 3) (stream->list (stream-drop-while negative? strm123))) + + ;; stream-filter + (test-error ; "stream-filter: non-procedural argument" + (stream-filter "four" strm123)) + (test-error (stream-filter odd? '())) ; "stream-filter: non-stream argument" + (test #t (stream-null? (stream-filter odd? (stream)))) + (test '(1 3) (stream->list (stream-filter odd? strm123))) + (test '(2) (stream->list (stream-filter even? strm123))) + (test '(1 2 3) (stream->list (stream-filter positive? strm123))) + (test '() (stream->list (stream-filter negative? strm123))) + (let loop ((n 10)) + (test #t (odd? (stream-ref (stream-filter odd? (stream-from 0)) n))) + (if (positive? n) (loop (- n 1)))) + (let loop ((n 10)) + (test #f (even? (stream-ref (stream-filter odd? (stream-from 0)) n))) + (if (positive? n) (loop (- n 1)))) + + ;; stream-fold + (test-error ; "stream-fold: non-procedural argument" + (stream-fold "four" 0 strm123)) + (test-error (stream-fold + 0 '())) ; "stream-fold: non-stream argument" + (test 6 (stream-fold + 0 strm123)) + + ;; stream-for-each + (test-error ; "stream-for-each: non-procedural argument" + (stream-for-each "four" strm123)) + (test-error ; "stream-for-each: no stream arguments" + (stream-for-each +)) + (test-error ; "stream-for-each: non-stream argument" + (stream-for-each + "four")) + (test 6 + (let ((sum 0)) + (stream-for-each (lambda (x) (set! sum (+ sum x))) strm123) + sum)) + + ;; stream-from + (test-error (stream-from "four")) ; "stream-from: non-numeric starting number" + (test-error (stream-from 1 "four")) ; "stream-from: non-numeric step size" + (test 100 (stream-ref (stream-from 0) 100)) + (test 201 (stream-ref (stream-from 1 2) 100)) + (test -100 (stream-ref (stream-from 0 -1) 100)) + + ;; stream-iterate + (test-error (stream-iterate "four" 0)) ; "stream-iterate: non-procedural argument" + (test '(1 2 3) (stream->list 3 (stream-iterate (lsec + 1) 1))) + + ;; stream-length + (test-error (stream-length "four")) ; "stream-length: non-stream argument" + (test 0 (stream-length (stream))) + (test 3 (stream-length strm123)) + + ;; stream-let + (test '(2 4 6) + (stream->list + (stream-let loop ((strm strm123)) + (if (stream-null? strm) + stream-null + (stream-cons + (* 2 (stream-car strm)) + (loop (stream-cdr strm))))))) + + ;; stream-map + (test-error (stream-map "four" strm123)) ; "stream-map: non-procedural argument" + (test-error (stream-map odd?)) ; "stream-map: no stream arguments" + (test-error (stream-map odd? "four")) ; "stream-map: non-stream argument" + (test '(-1 -2 -3) (stream->list (stream-map - strm123))) + (test '(2 4 6) (stream->list (stream-map + strm123 strm123))) + (test '(2 4 6) (stream->list (stream-map + strm123 (stream-from 1)))) + (test '(2 4 6) (stream->list (stream-map + (stream-from 1) strm123))) + (test '(3 6 9) (stream->list (stream-map + strm123 strm123 strm123))) + + ;; stream-match + (test-error (stream-match '(1 2 3) (_ 'ok))) ; "stream-match: non-stream argument" + (test-error (stream-match strm123 (() 42))) ; "stream-match: pattern failure" + (test 'ok (stream-match stream-null (() 'ok))) + (test 'ok (stream-match strm123 (() 'no) (else 'ok))) + (test 1 (stream-match (stream 1) (() 'no) ((a) a))) + (test 'ok (stream-match (stream 1) (() 'no) ((_) 'ok))) + (test '(1 2 3) (stream-match strm123 ((a b c) (list a b c)))) + (test 1 (stream-match strm123 ((a . _) a))) + (test '(1 2) (stream-match strm123 ((a b . _) (list a b)))) + (test '(1 2 3) + (stream-match strm123 ((a b . c) (list a b (stream-car c))))) + (test '(1 2 3) (stream-match strm123 (s (stream->list s)))) + (test 'ok (stream-match strm123 ((a . _) (= a 1) 'ok))) + (test 'no (stream-match strm123 ((a . _) (= a 2) 'yes) (_ 'no))) + (test 'no (stream-match strm123 ((a b c) (= a b) 'yes) (_ 'no))) + (test 'yes (stream-match (stream 1 1 2) ((a b c) (= a b) 'yes) (_ 'no))) + + ;; stream-of + (test '(7 15 31) + (stream->list + (stream-of (+ y 6) + (x in (stream-range 1 6)) + (odd? x) + (y is (* x x))))) + (test '(1 2 3 4 2 4 6 8 3 6 9 12) + (stream->list + (stream-of (* x y) + (x in (stream-range 1 4)) + (y in (stream-range 1 5))))) + (test 1 (stream-car (stream-of 1))) + + ;; stream-range + (test-error (stream-range "four" 0)) ; "stream-range: non-numeric starting number" + (test-error (stream-range 0 "four")) ; "stream-range: non-numeric ending number" + (test-error (stream-range 1 2 "three")) ; "stream-range: non-numeric step size" + (test '(0 1 2 3 4) (stream->list (stream-range 0 5))) + (test '(5 4 3 2 1) (stream->list (stream-range 5 0))) + (test '(0 2 4) (stream->list (stream-range 0 5 2))) + (test '(5 3 1) (stream->list (stream-range 5 0 -2))) + (test '() (stream->list (stream-range 0 1 -1))) + + ;; stream-ref + (test-error (stream-ref '() 4)) ; "stream-ref: non-stream argument" + (test-error (stream-ref nats 3.5)) ; "stream-ref: non-integer argument" + (test-error (stream-ref nats -3)) ; "stream-ref: negative argument" + (test-error (stream-ref strm123 5)) ; "stream-ref: beyond end of stream" + (test 1 (stream-ref strm123 0)) + (test 2 (stream-ref strm123 1)) + (test 3 (stream-ref strm123 2)) + + ;; stream-reverse + (test-error (stream-reverse '())) ; "stream-reverse: non-stream argument" + (test '() (stream->list (stream-reverse (stream)))) + (test '(3 2 1) (stream->list (stream-reverse strm123))) + + ;; stream-scan + (test-error ; "stream-scan: non-procedural argument" + (stream-scan "four" 0 strm123)) + (test-error (stream-scan + 0 '())) ; "stream-scan: non-stream argument" + (test '(0 1 3 6) (stream->list (stream-scan + 0 strm123))) + + ;; stream-take + (test-error (stream-take 5 "four")) ; "stream-take: non-stream argument" + (test-error (stream-take "four" strm123)) ; "stream-take: non-integer argument" + (test-error (stream-take -4 strm123)) ; "stream-take: negative argument" + (test '() (stream->list (stream-take 5 stream-null))) + (test '() (stream->list (stream-take 0 stream-null))) + (test '() (stream->list (stream-take 0 strm123))) + (test '(1 2) (stream->list (stream-take 2 strm123))) + (test '(1 2 3) (stream->list (stream-take 3 strm123))) + (test '(1 2 3) (stream->list (stream-take 5 strm123))) + + ;; stream-take-while + (test-error ; "stream-take-while: non-stream argument" + (stream-take-while odd? "four")) + (test-error ; "stream-take-while: non-procedural argument" + (stream-take-while "four" strm123)) + (test '(1) (stream->list (stream-take-while odd? strm123))) + (test '() (stream->list (stream-take-while even? strm123))) + (test '(1 2 3) (stream->list (stream-take-while positive? strm123))) + (test '() (stream->list (stream-take-while negative? strm123))) + + ;; stream-unfold + (test-error ; "stream-unfold: non-procedural mapper" + (stream-unfold "four" odd? + 0)) + (test-error ; "stream-unfold: non-procedural pred?" + (stream-unfold + "four" + 0)) + (test-error ; "stream-unfold: non-procedural generator" + (stream-unfold + odd? "four" 0)) + (test '(0 1 4 9 16 25 36 49 64 81) + (stream->list (stream-unfold (rsec expt 2) (rsec < 10) (rsec + 1) 0))) + + ;; stream-unfolds + (test + '(0 1 2 3 4) + (stream->list + (stream-unfolds + (lambda (x) + (let ((n (car x)) (s (cdr x))) + (if (zero? n) + (values 'dummy '()) + (values + (cons (- n 1) (stream-cdr s)) + (list (stream-car s)))))) + (cons 5 (stream-from 0))))) + + ;; stream-zip + (test-error (stream-zip)) ; "stream-zip: no stream arguments" + (test-error (stream-zip "four")) ; "stream-zip: non-stream argument" + (test-error (stream-zip strm123 "four")) ; "stream-zip: non-stream argument" + (test '() (stream->list (stream-zip strm123 stream-null))) + (test '((1) (2) (3)) (stream->list (stream-zip strm123))) + (test '((1 1) (2 2) (3 3)) (stream->list (stream-zip strm123 strm123))) + (test '((1 1) (2 2) (3 3)) + (stream->list (stream-zip strm123 (stream-from 1)))) + (test '((1 1 1) (2 2 2) (3 3 3)) + (stream->list (stream-zip strm123 strm123 strm123))) + + (test-end)))) diff --git a/tests/lib-tests.scm b/tests/lib-tests.scm index 2f72d0cb..edceb688 100644 --- a/tests/lib-tests.scm +++ b/tests/lib-tests.scm @@ -9,6 +9,7 @@ (rename (srfi 26 test) (run-tests run-srfi-26-tests)) (rename (srfi 27 test) (run-tests run-srfi-27-tests)) (rename (srfi 38 test) (run-tests run-srfi-38-tests)) + (rename (srfi 41 test) (run-tests run-srfi-41-tests)) (rename (srfi 69 test) (run-tests run-srfi-69-tests)) (rename (srfi 95 test) (run-tests run-srfi-95-tests)) (rename (srfi 99 test) (run-tests run-srfi-99-tests)) @@ -62,6 +63,7 @@ (run-srfi-26-tests) (run-srfi-27-tests) (run-srfi-38-tests) +(run-srfi-41-tests) (run-srfi-69-tests) (run-srfi-95-tests) (run-srfi-99-tests)