Trouble with streams in Scheme - stream

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.

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)))))

Related

SICP 3.52 delayed cdr

Exercise 3.52,
(define sum 0)
(define (accum x)
(set! sum (+ x sum))
sum)
;1: (define seq (stream-map accum (stream-enumerate-interval 1 20)))
;2: (define y (stream-filter even? seq))
;3: (define z (stream-filter (lambda (x) (= (remainder x 5) 0))
; seq))
;4: (stream-ref y 7)
;5: (display-stream z)
Step 1:
;1: ==> (cons-stream 1 (stream-map proc (stream-cdr s)) (Assume stream-cdr is evaluated only when we force the cdr of this stream)
sum is now 1
Step 2:
1 is not even, hence (also memoized so not added again), it calls (stream-filter pred (stream-cdr stream)).
This leads to
evaluation of cdr hence materializing 2 which is even, hence it should call: (cons-stream 2 (stream-cdr stream)).
According to this answer should be 1+2 = 3 , but it is 6
Can someone help with why the cdr's car is materialized before the current cdr is called?
Using Daniel P. Friedman's memoizing tail
#lang r5rs
(define-syntax cons-stream
(syntax-rules ()
((_ h t) (cons h (lambda () t)))))
(define (stream-cdr s)
(if (and (not (pair? (cdr s)))
(not (null? (cdr s))))
(set-cdr! s ((cdr s))))
(cdr s))
we observe:
> sum
0
> (define seq (stream-map accum (stream-enumerate-interval 1 20)))
> sum
1
> seq
(mcons 1 #<procedure:friedmans-tail.rkt:21:26>)
> (define y (stream-filter even? seq))
> sum
6
> seq
(mcons
1
(mcons
3
(mcons 6 #<procedure:friedmans-tail.rkt:21:26>)))
> y
(mcons 6 #<procedure:friedmans-tail.rkt:21:26>)
>
stream-filter? needs to get to the first element of the stream it is constructing in order to construct it. A stream has its head element already forced, calculated, so it must be already present.
In the list of accumulated sums of the enumerated interval from 1 to 20, the first even number is 6:
1 = 1
1+2 = 3
1+2+3 = 6
...

Write a stream of sexy prime pairs in SCHEME

I have a SCHEME function is-sexy? which takes one parameter, n, and returns true if n is part of a pair of sexy primes and false otherwise, and a SCHEME function, sexy-primes, which takes an integer, n, as a parameter and returns a list of pairs of prime numbers whose difference is 6 and whose smaller number is less than or equal to n.
How do I define a stream of sexy prime pairs?
(define (is-sexy? n)
(define (is-prime? x)
(define (is-prime?-aux x k)
(cond ((< x 1) #f)
((= x k) #t)
(else
(if (= (remainder x k) 0) #f
(is-prime?-aux x (+ k 1))))))
(cond ((= x 1) #t)
((= x 2) #t)
(else (is-prime?-aux x 2))))
(if (and (is-prime? n)
(or (is-prime? (- n 6)) (is-prime? (+ n 6)))) #t
#f))
(define (sexy-primes n)
(if (= n 0) '()
(if (is-sexy? n) (cons n (sexy-primes (- n 1)))
(sexy-primes (- n 1)))))
This works:
(define (sexyprimes-from k)
(if (is-sexy? k) (cons (cons k (+ k 6)) (delay (sexyprimes-from (+ k 1))))
(sexyprimes-from (+ k 1))))
(define sexy-primes (sexyprimes-from 5))

An iterative program for appending lists in scheme

I am reading Section 2.2 in SICP where the book introduced the procedure for appending two lists. I am trying to implement the append using iteration.
This is my code:
(define (append list1 list2)
(define (append-iter item1 reversed-item1 result)
(if (null? item1)
(if (null? reversed-item1)
result
(append-iter item1
(cdr reversed-item1)
(cons (car reverse) result)))
(append-iter (cdr item1)
(cons (car item1) reversed-item1)
result)))
(append-iter list1 '() list2))
Though it works, but noting the number of the iterations is double the length of list1. Is there a solution whose number of the iterations equals to the length of list1. (without using any fold function)?
Basically how your procedure works is like this:
(define (append l1 l2)
(define (reverse-append rev app)
(if (null? rev)
app
(reverse-append (cdr rev)
(cons (car rev) app))))
(reverse-append (reverse l1) l2))
It's O(N) but it wastes some memory since (reverse l1) space is just used for iteration. If you really need to fix that you need to use mutation:
(define (append-iter . rest)
(let ((result (list 1)))
(let loop ((p result) (lst '()) (rest rest))
(cond
((not (null? lst))
(set-cdr! p (list (car lst)))
(loop (cdr p) (cdr lst) rest))
((null? rest) (cdr result))
((null? (cdr rest))
(set-cdr! p (car rest))
(cdr result))
(else (loop p (car rest) (cdr rest)))))))

Give a stream of numbers in scheme I need to print n numbers separated by comma like (1, 2, 3, 4, ..)

I can print n-numbers as list with this code below:
(define (print-first-n stream1 n)
(cond((= n 0) '())
(else(cons(stream-car stream1) (print-first-n (stream-cdr stream1) (- n 1))))))
But I have no idea about how to add commas.
You can't print a comma in a normal list, but we can build a string with the contents of the stream, separated by commas. This will work, assuming that the string contains numbers:
(define (print-first-n stream1 n)
(cond ((= n 1)
(number->string (stream-car stream1)))
(else
(string-append
(number->string (stream-car stream1)) ", "
(print-first-n (stream-cdr stream1) (- n 1))))))
The above solution is fine for a small value of n, but terribly inefficient for large values (lots of temporary strings will be created, with O(n^2) complexity for the append operation). For a more efficient implementation, consider using SRFI-13's concatenation procedures, like this:
(require srfi/13)
(define (print-first-n stream1 n)
(let loop ((strm stream1) (n n) (acc '()))
(if (= n 1)
(string-concatenate-reverse
(cons (number->string (stream-car strm)) acc))
(loop (stream-cdr strm)
(sub1 n)
(list* ", " (number->string (stream-car strm)) acc)))))
Either way: let's say that integers is an infinite stream of integers starting at 1, this is how it would look:
(print-first-n integers 5)
=> "1, 2, 3, 4, 5"
If the stream contains some other data type, use the appropriate procedure to convert each element to a string.
If your function just prints the stream contents, and doesn't need to build a string (like Óscar's answer), here's my take on it (uses SRFI 41 streams):
(define (print-first-n stream n)
(stream-for-each (lambda (delim item)
(display delim)
(display item))
(stream-cons "" (stream-constant ", "))
(stream-take n stream)))
Example:
> (define natural (stream-cons 1 (stream-map (lambda (x) (+ x 1)) natural)))
> (print-first-n natural 10)
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
To output to a string (like Óscar's answer), just wrap the whole thing in a string port:
(define (print-first-n stream n)
(call-with-output-string
(lambda (out)
(stream-for-each (lambda (delim item)
(display delim out)
(display item out))
(stream-cons "" (stream-constant ", "))
(stream-take n stream)))))

Recursion in a stream

I have the code
(define (add-ten s)
(let ([f (lambda(s) ((cons 10 (car (s))) (cdr (s))))])
(f s)))
s could be a stream like powers
(define powers (letrec ([f (lambda (x) (cons x (lambda () (f (* x 2)))))])
(lambda () (f 2))))
My function
(result-for-n-times powers 5)
gives '(2 4 8 16 32).
Now, i want to define a stream (add-ten) that can take the stream powers and gives another stream.So, if i call it
(result-for-n-times (add-ten powers) 5)
would give '((10. 2) (10. 4) (10. 8) (10. 16) (10. 32)).
Try this:
(define powers
(letrec ([f (lambda (x)
(cons x
(lambda () (f (* x 2)))))])
(f 2)))
(define (result-for-n-times s n)
(if (zero? n)
'()
(cons (car s)
(result-for-n-times ((cdr s)) (sub1 n)))))
(define (add-ten s)
(letrec ([f (lambda (x)
(cons (cons 10 (car x))
(lambda () (f ((cdr x))))))])
(f s)))
Notice that the add-ten procedure receives a stream as a parameter, but also it must return a stream. So letrec must be used for defining a procedure that conses each element taken from the original stream, with a promise that keeps on building the stream.
Also notice that you're not actually calling the procedure that defines powers, you either call it at the end of powers' definition or you call it like this: (powers) before passing it to add-ten. Fixing this, it works as expected:
(result-for-n-times (add-ten powers) 5)
=> '((10 . 2) (10 . 4) (10 . 8) (10 . 16) (10 . 32))

Resources