We use SG (Stream Generator) consistently to characterize a Scheme value that presents some particular stream of values z0, z1, ... zn, according to the following logic: ((Z)) => z0, (let ((r (Z))) (r) (r)) => z1 etc. Z is immutable while (Z) yields a procedure which yields the successive elements of the stream on successive calls and yields #f after yielding zn. Successive calls to Z always yield a new generator just like the last.

Routines SG->lst & lst->SG convert between Scheme lists and streams. (fs sg fil) takes an SG and a filter (element predicate) and returns another SG that produces the elements that pass the filter. (Cart g h) takes two such SG’s and returns a third for the Cartesian product, which produces pairs.

; map each element of a stream by fun for another stream.
(define (sm sg fun)(lambda () (let ((s (sg))) (lambda ()
    (let ((ne (s))) (and ne (fun ne)))))))
; Stream of integers thru k-1
(define (si k) (lambda () (let ((n 0)) (lambda ()
    (and (< n k) (let ((i n)) (set! n (+ n 1)) i))))))
(define (SG->lst sg) (reverse (let ((g (sg))) (let w ((e (g))(lst '()))
          (if e (w (g) (cons e lst)) lst)))))
(define (lst->SG l) (lambda () (let ((c l)) (lambda () (and (pair? c)
     (let ((v (car c))) (begin (set! c (cdr c)) v)))))))
; filtered substream:
(define (fs sg fil) (lambda () (let ((sc (sg))) (lambda ()
      (let scan () (let ((ne (sc))) (and ne (if (fil ne) ne (scan)))))))))
; Cartesian product of two streams, streamed.
(define (Cart g h) (lambda () (let* ((G (g))(H (h))(gs (G)))
   (lambda () (let ((n (H)))
      (if (not n) (begin (set! H (h)) (set! gs (G)) (set! n (H))))
      (and gs (cons gs n)))))))
; String to Stream converter.
(define (str->str st) (let ((l (string-length st)))
     (lambda () (let ((n 0)) (lambda () (and (< n l)
        (let ((ch (string-ref st n))) (set! n (+ n 1)) ch)))))))
(SG->lst (fs (si 25) odd?)) ; => (1 3 5 7 9 11 13 15 17 19 21 23)
(SG->lst (Cart (si 2)(si 3))) ; => ((0 . 0) (0 . 1) (0 . 2) (1 . 0) (1 . 1) (1 . 2))
(SG->lst (sm (si 6) -)) ; => (0 -1 -2 -3 -4 -5)
(SG->lst (str->str "flub")) ; => (#\f #\l #\u #\b)