;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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: