From SICP:
This is an infinite stream of ones:
(define ones (cons-stream 1 ones))
This is an infinite stream of positive integers:
; add-streams takes two streams and produces a stream of their elementwise sum
(define integers (cons-stream 1 (add-streams ones integers)))
interleave takes elements alternately from two streams and returns the result
(define (interleave s1 s2)
(if (stream-null? s1)
s2
(cons-stream
(stream-car s1)
(interleave s2 (stream-cdr s1)))))
The following pairs procedure takes two streams s and t, and produces all pairs (s_i, t_j) such that i <= j.
(define (pairs s t)
(cons-stream
(list (stream-car s) (stream-car t))
(interleave
(stream-map (lambda (x)
(list (stream-car s) x))
(stream-cdr t))
(pairs (stream-cdr s) (stream-cdr t)))))
So
(pairs integers integers)
produces all pairs of integers i and j with i <= j.
Here is exercise 3.67:
Exercise 3.67: Modify the pairs procedure so that (pairs integers
integers) will produce the stream of all pairs of integers (i, j)
(without the condition (i <= j)). Hint: You will need to mix in an
additional stream.
My solution is:
(define (pairs2 s t)
(cons-stream
(list (stream-car s) (stream-car t))
(interleave
(stream-map (lambda (x)
(list (stream-car s) x))
(stream-cdr t))
(pairs2 (stream-cdr s) t))))
So, I just changed (stream-cdr t) to t in the last recursive call. This appears to produce all pairs of integers.
What I don't understand is the statement:
Hint: You will need to mix in an additional stream.
What does this mean? Is my solution wrong? What do they mean when they say an additional stream?
Using my modified pairs2 procedure, these are the first 20 results:
> (define p2 (pairs2 integers integers))
> (stream-ref p2 0)
(1 1)
> (stream-ref p2 1)
(1 2)
> (stream-ref p2 2)
(2 1)
> (stream-ref p2 3)
(1 3)
> (stream-ref p2 4)
(2 2)
> (stream-ref p2 5)
(1 4)
> (stream-ref p2 6)
(3 1)
> (stream-ref p2 7)
(1 5)
> (stream-ref p2 8)
(2 3)
> (stream-ref p2 9)
(1 6)
> (stream-ref p2 10)
(3 2)
> (stream-ref p2 11)
(1 7)
> (stream-ref p2 12)
(2 4)
> (stream-ref p2 13)
(1 8)
> (stream-ref p2 14)
(4 1)
> (stream-ref p2 15)
(1 9)
> (stream-ref p2 16)
(2 5)
> (stream-ref p2 17)
(1 10)
> (stream-ref p2 18)
(3 3)
> (stream-ref p2 19)
(1 11)
It appears that your answer is indeed correct. For what is worth, I was able to solve it using one extra stream, which is what the authors meant with the hint "You will need to mix in an additional stream":
(define (pairs s t)
(cons-stream
(list (stream-car s) (stream-car t))
(interleave (stream-map (λ (x) (list (stream-car s) x))
(stream-cdr t))
(interleave (stream-map (λ (x) (list x (stream-car t)))
(stream-cdr s))
(pairs (stream-cdr s) (stream-cdr t))))))
My first 20 results are similar, although in some cases in different order or with different elements that will probably appear later on in your solution:
(1 1)
(1 2)
(2 1)
(1 3)
(2 2)
(1 4)
(3 1)
(1 5)
(2 3)
(1 6)
(4 1)
(1 7)
(3 2)
(1 8)
(5 1)
(1 9)
(2 4)
(1 10)
(6 1)
(1 11)
Related
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
...
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)))))
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))
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)))))
I have the code
(define alternate
(letrec ([f (lambda (x) (cons x (lambda () (f (+ x 1)))))])
(lambda () (f 1))))
The result is 1,2,3..
How i could change it to take 1,2,1,2,1,2..
I tried cons inside the f but didn't work.
Any ideas?
You might also find generators useful: docs
Welcome to DrRacket, version 5.3.3.5 [3m].
Language: racket [custom].
> (require racket/generator)
> (define g (generator () (let LOOP () (yield 1) (yield 2) (LOOP))))
> (g)
1
> (g)
2
> (g)
1
> (g)
2
UPDATE:
Even better, use an infinite-generator:
Welcome to DrRacket, version 5.3.3.5 [3m].
Language: racket [custom].
> (require racket/generator)
> (define g (infinite-generator (yield 1) (yield 2)))
> (g)
1
> (g)
2
> (g)
1
> (g)
2
This is straightforward to implement using streams:
(define (alternate)
(stream-map (lambda (x)
(if (even? x) 1 2))
(in-naturals)))
The trick here is that a stream is built using stream-cons, which basically does what you're implementing by hand: it creates a list where its elements are "promises" that get evaluated only when needed.
stream-cons produces a lazy stream for which stream-first forces the evaluation of first-expr to produce the first element of the stream, and stream-rest forces the evaluation of rest-expr to produce a stream for the rest of the returned stream.
This shows how alternate returns an infinite stream of elements of the form 1 2 1 2 1 2 ...
(define alt (alternate))
(stream-ref alt 0)
=> 1
(stream-ref alt 1)
=> 2
(stream-ref alt 2)
=> 1
(stream-ref alt 3)
=> 2
Alternatively, if you need a list of n elements of the sequence use this procedure, which by the way should be part of Racket in the first place:
(define (stream-take s n)
(if (zero? n)
'()
(cons (stream-first s)
(stream-take (stream-rest s) (sub1 n)))))
Now it works as expected:
(define alt (alternate))
(stream-take alt 0)
=> '()
(stream-take alt 1)
=> '(1)
(stream-take alt 2)
=> '(1 2)
(stream-take alt 3)
=> '(1 2 1)
Here's a way to do it as a small modification of your existing code:
(define alternate
(letrec ([f (lambda (x) (cons x (lambda () (f (if (= x 1) 2 1)))))])
(lambda () (f 1))))