I am trying to write a procedure stream-weighted-tuples
that takes a weight procedure and any number of streams, to generate a stream of tuples.
For instance,
(stream-weighted-tuples
(lambda (t) (+ (car t) (cadr t) (caddr t))
integers
integers
integers)
should generate a stream of (1 1 1) (1 1 2) (1 2 1) (2 1 1) (1 1 3) (1 2 2) (1 3 1) (2 1 2) (2 2 1) (3 1 1) (1 1 4) (1 2 3) ...
.
I was inspired by exercise 3.70 in SICP, which is about writing a procedure weighted-pairs
that takes two streams and a weight procedure to generate a stream of pairs in the order according to weight.
So basically, this is a generalization of the weighted-pairs
procedure to take more than two streams.
I wrote the following version:
(define (stream-weighted-tuples weight . streams)
(cond ((null? streams)
(error "No streams given -- STREM-WEIGHTED-TUPLES"))
((null? (cdr streams))
(stream-map list (car streams)))
(else
(let ((s (car streams))
(rest (cdr streams)))
(if (stream-null? s)
the-empty-stream ; {} x S = {}
(stream-merge-weighted
weight
(stream-map (lambda (tuple)
(cons (stream-car s) tuple))
(apply stream-weighted-tuples
(lambda (tuple) ; partial weight
(weight (cons (stream-car s)
tuple)))
rest))
(apply stream-weighted-tuples
weight
(stream-cdr s)
rest)))))))
(which apparently doesn’t work).
The idea was to merge 1. the stream resulting from cons
ing the first element of the first stream with each element of the (recursively constructed) stream that consists of the tuples from the rest of the given streams, and 2. the stream that consists of the tuples of the stream-cdr
of the first stream and the rest of the given streams.
This doesn’t work because generating stream 2 won’t halt in the case of an infinite stream (due to the same reason pairs
procedure from exercise 3.68 doesn’t work).
This is stream-merge-weighted
I implemented:
(define (stream-merge-weighted weight s1 s2)
(cond ((stream-null? s1) s2)
((stream-null? s2) s1)
(else
(let* ((s1car (stream-car s1))
(s2car (stream-car s2))
(s1car-weight (weight s1car))
(s2car-weight (weight s2car)))
(cond ((<= s1car-weight s2car-weight)
(cons-stream
s1car
(stream-merge-weighted weight
(stream-cdr s1)
s2)))
((> s1car-weight s2car-weight)
(cons-stream
s2car
(stream-merge-weighted weight
s1
(stream-cdr s2)))))))))
Is there a way to recursively construct this problem?
EDIT: What I meant by “tuple” in this question is actually a Scheme list that semantically represents a tuple.
For reference, I leave my implementation of stream primitives (which is identical to the ones in SICP):
(define-syntax cons-stream
(syntax-rules ()
((_ a b)
(cons a (delay b)))))
(define (stream-car stream)
(car stream))
(define (stream-cdr stream)
(force (cdr stream)))
(define (stream-null? stream)
(null? stream))
(define the-empty-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)))))
I managed to solve it using a recursion structure similar to that of the pairs
procedure shown in SICP.
The following stream-weighted-tuples
works with recursively constructed stream of tuples of the cdr
of streams (rest-tuples
), and then uses the same recursion strategy to “pair” (unlike the original pair
procedure, the other stream is already a stream of tuples) it with the car
of streams (combine-with-rest
).
(define (stream-weighted-tuples weight . streams)
(if (null? streams)
(cons-stream '() the-empty-stream)
(let* ((stream (car streams))
(rest (cdr streams))
(rest-tuples
(apply stream-weighted-tuples
(lambda (tuple) ; partial weight
(weight (cons (stream-car stream) tuple)))
rest)))
(let combine-with-rest ((stream stream)
(rest-tuples rest-tuples))
(if (or (stream-null? stream)
(stream-null? rest-tuples))
the-empty-stream ; {} x S = {}
(let ((s-car (stream-car stream))
(s-cdr (stream-cdr stream))
(r-car (stream-car rest-tuples))
(r-cdr (stream-cdr rest-tuples)))
(cons-stream (cons s-car r-car)
(stream-merge-weighted
weight
(stream-map (lambda (t) (cons s-car t))
r-cdr)
(stream-merge-weighted
weight
(stream-map (lambda (x) (cons x r-car))
s-cdr)
(combine-with-rest s-cdr r-cdr))))))))))
Note, that the weight
procedure requires the cdr
of tuples to be ordered independent to the car
s, i.e., W(a, b, c) >= W(x, y, z) only if W(b, c) >= W(y, z).