[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(stream-cons (1) stream-null) => stream



There is a serious bug in the reference implementation of SRFI 40, which can be demonstrated by the following expression:

   (stream-cons (1) stream-null)

According to the specification, this should evaluate to a stream. The reference implementation, however, will evaluate (1), which is an error.

The following results are all calculated incorrectly by the reference implementation (I've written what the expression should evaluate to, according to the specification):

   (stream-cons (1) stream-null)                 ;=> stream
   (stream-null? (stream-cons (1) stream-null))  ;=> #f
   (stream-pair? (stream-cons (1) stream-null))  ;=> #t
   (stream-cdr (stream-cons (1) stream-null))    ;=> stream
   (stream-null? (stream-cdr (stream-cons (1) stream-null)))
                                                 ;=> #t
   (stream-cons #t #f)                           ;=> error

I believe the following definitions of STREAM-CONS and STREAM-CAR will fix the problem; it gives correct results for the above examples:

;; STREAM-CONS object stream -- primitive constructor of streams
(define-syntax stream-cons
  (syntax-rules ()
    ((stream-cons obj strm)
     (srfi-40:eager
      (if (not (stream? strm))
          (stream-error "attempt to stream-cons onto non-stream")
          (cons (delay obj) strm))))))

;; STREAM-CAR stream -- first element of stream
(define (stream-car strm)
  (cond ((not (stream? strm))
         (stream-error "attempt to take stream-car of non-stream"))
        ((stream-null? strm)
         (stream-error "attempt to take stream-car of null stream"))
        (else (force (car (srfi-40:force (stream-promise strm)))))))

Currently, these are given as:

;; STREAM-CONS object stream -- primitive constructor of streams
(define-syntax stream-cons
  (syntax-rules ()
    ((stream-cons obj strm)
     (make-stream
      (srfi-40:delay
       (if (not (stream? strm))
           (stream-error "attempt to stream-cons onto non-stream")
           (cons obj strm)))))))

;; STREAM-CAR stream -- first element of stream
(define (stream-car strm)
  (cond ((not (stream? strm))
         (stream-error "attempt to take stream-car of non-stream"))
        ((stream-null? strm)
         (stream-error "attempt to take stream-car of null stream"))
        (else (car (srfi-40:force (stream-promise strm))))))

Before patching the reference implementation, I'd appreciate any reviews or comments on this change. I know there are subtle space issues, which I may have overlooked.

It's remarkable to me that this issue has not come up before.

David