Warm tip: This article is reproduced from serverfault.com, please click

Trouble with streams in Scheme

发布于 2020-12-01 14:00:27

I'm trying to write a stream that takes as arguments an infinite stream S, and two integers m and n, and returns the stream whose elements are elements of S that are multiples of either m or n.

Unfortunately, my stream only works until I find the first multiple, then it won't progress past that. I'm calling the cdr when invoking the stream, so I'm not sure why I'm not looking at the next element.

(define stream-car car)
(define (stream-cdr s)
  ((cadr s)))

(define (divisible? n x)
  (zero? (remainder n x)))
(define (stream-cons x s)
  (list x (lambda () s)))

;should loop to find the next multiple in the parameter stream
(define (findnext s m n)
  (if (or (divisible? (stream-car s) m) 
          (divisible? (stream-car s) n))
      (stream-car s)
      (findnext (stream-cdr s) m n)))

;this is my stream
(define (multiples s m n)
  (let ((h (findnext s m n))) 
        ;first need to make sure h is a multiple of 
        ;either m or n, THEN create the list
    (list h
          (lambda ()
            (multiples (stream-cdr s) m n)))))

;below is for testing 
(define (even-nums-from n)
  (list n
        (lambda ()
          (even-nums-from (+ 2 n)))))

(define even-integers
  (even-nums-from 0))

;test cases
(multiples even-integers 4 6);should be a stream with car = 0
(stream-car (multiples even-integers 4 6));should be 0
(stream-cdr (multiples even-integers 4 6));should be a stream with car = 4
(stream-car (stream-cdr (multiples even-integers 4 6))) ;should be 4
(stream-cdr (stream-cdr (multiples even-integers 4 6))) ;should be a stream 
                ;starting with 6-not moving past when we find a multiple
(stream-car (stream-cdr (stream-cdr (multiples even-integers 4 6))))
                ;should be 6 

My output for the above tests is:

(list 0 (lambda () ...))
0
(list 4 (lambda () ...))
4
(list 4 (lambda () ...))
4

I'm using DrRacket (advanced student language) and just not sure why my stream is stuck on that first multiple (4). I'm calling stream-cdr when I invoke multiples again, so I don't understand where I'm going wrong. Any ideas would be much appreciated.

Questioner
Ben
Viewed
0
60.9k 2020-12-01 23:18:10

Solved it, the problem was I was not updating the passed stream as I found the next multiple. Below is the corrected code (where I now pass a stream with the multiple in the car that will be used in my multiples function):

;returns the stream with car a multiple of either m or n
(define (findnext s m n)
  (cond ((divisible? (stream-car s) m) s)
        ((divisible? (stream-car s) n) s)      
        (else (findnext (stream-cdr s) m n))))

(define (multiples s m n)
  (let ((h (findnext s m n))) ;h is now an updated stream 
                              ;with car a multiple of one of m or n
    (list (stream-car h)
          (lambda ()
            (multiples (stream-cdr h) m n)))))