;; Most of this is stolen from SICP (define the-empty-stream '()) (define (stream-null? s) (null? s)) (define (stream-car s) (car s)) (define (stream-cdr s) (force (cdr s))) (define-syntax cons-stream (syntax-rules () ((cons-stream a d) (cons a (delay d))))) (define (stream-filter pred stream) (cond ((stream-null? stream) the-empty-stream) ((pred (stream-car stream)) (cons-stream (stream-car stream) (stream-filter pred (stream-cdr stream)))) (else (stream-filter pred (stream-cdr stream))))) (define (stream-map proc s) (if (stream-null? s) the-empty-stream (cons-stream (proc (stream-car s)) (stream-map proc (stream-cdr s))))) (define (adjoin-streams s1 s2) (cond ((stream-null? s1) s2) ((stream-null? s2) s1) (else (cons-stream (stream-car s1) (adjoin-streams s2 (stream-cdr s1)))))) (define (flatten ss) (if (stream-null? ss) the-empty-stream (adjoin-streams (stream-car ss) (flatten (stream-cdr ss))))) (define (flatmap f s) (flatten (stream-map f s))) (define (stream-enumerate-interval low high) (if (> low high) the-empty-stream (cons-stream low (stream-enumerate-interval (+ low 1) high)))) ;; macro by siraben (define-syntax collect (syntax-rules () ;; Just one iterator. Simple case. ;; The bound variable could occur free in the collector and filter. ((_ collector ((bound-var1 iterator1)) filter) (stream-map (lambda (bound-var1) collector) (stream-filter (lambda (bound-var1) filter) iterator1))) ((_ collector ((bound-var1 iterator1) (bound-var2 iterator2) ...) filter) (flatmap (lambda (bound-var1) ;; Make the first bound variable available to the rest of the ;; body (because it could occur free in the second iterator.) (collect collector ((bound-var2 iterator2) ...) filter)) iterator1)))) ;; example usage (define (evens n) (collect a ((a (range 1 n))) (even? a))) (define (prime-sum-pairs n) (collect (list i j (+ i j)) ((i (range 1 n)) (j (range 1 (- i 1)))) (prime? (+ i j))))