views:

134

answers:

1

The Scheme implementation of map takes N+1 arguments: a procedure of N arguments, and N lists. Further, it terminates mapping when the end of the shortest list is reached.

An alternative is to provide a default value for each list, which will be treated as the next element(s) of each list if it turns out to be shorter than the others.

That is define a procedure streem-map which takes as its arguments:
a procedure of N arguments
a list of N elements, which is the default value for the Nth stream
N streams

Streem-map produces a stream where the first element is the procedure applied to the (N) first elements of the streams, the second element is the same procedure applied to the second elements of the streams, and so on. If the Nth stream becomes empty, streem-map uses the Nth default element. Therefore, the stream produced by streem-map will always have infinite length; if all of the N input streams are of finite length, eventually it will generate lists consisting of the procedure applied to the N default values.

For example:

(streem-map (lambda (x y z) (* x y z))
‘(0 1 2)
(list->streem ‘(1 2 3))
(list->streem ‘(9 9))
(list->streem ‘(4))

would generate the infinite stream consisting of: ‘(36 36 6 0 0 0 …)

+2  A: 

Let's first define a set of basic stream primitives, so that the rest of the code makes sense:

(define-syntax stream-cons
  (syntax-rules ()
    ((stream-cons obj expr)
     (cons obj (delay expr)))))

(define stream-car car)
(define (stream-cdr p) (force (cdr p)))
(define stream-null? null?)

With these we can define operations for "streems", our "better streams".

(define (streem-car stream default)
  (if (stream-null? stream) default (stream-car stream)))

(define (streem-cdr stream)
  (if (stream-null? stream) stream (stream-cdr stream)))

(define (streem-map proc defaults . streams)
  (stream-cons (apply proc (map streem-car streams defaults))
               (apply streem-map proc defaults (map streem-cdr streams))))

You should be able to easily adapt this to whatever stream library you are already using. You don't need a separate list->streem conversion, you can pass streem-map regular streams (presumably created with list->stream).

Ville Laurikari