Running code from SICP section 3.5.4 with DrRacket - scheme

I'm having trouble running an example code from SICP (Structure and Interpretation of Computer Programs) Section 3.5.4 (Streams and Delayed Evaluation); the SICP section can be found here: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%_sec_3.5.4.
I'm using DrRacket version 5.2.1, set up with the SICP support language by Neil Van Dyke (SICP PLaneT 1.17), which can be found here: http://www.neilvandyke.org/racket-sicp/#%28part._installation%29.
The code, shown below, makes use of streams. With the environment set up as above, the procedures cons-stream, force and delay are already available from DrRacket. But stream-car and stream-cdr weren't available; so, I had to define them. In the code below, I also define some generic stream functions: stream-map, stream-ref, add-streams and scale-stream.
The whole code I'm trying to make work is the following. It includes a procedure to solve first-order differential equations numerically (solve), using an integration procedure (integral), which uses a delayed argument (delayed-integrand); these procedures come from Section 3.5.4.
(define (stream-car stream) (car stream))
(define (stream-cdr stream) (force (cdr stream)))
(define (stream-map proc . argstreams)
(if (stream-null? (car argstreams))
the-empty-stream
(cons-stream
(apply proc (map stream-car argstreams))
(apply stream-map
(cons proc (map stream-cdr argstreams))))))
(define (stream-ref s n)
(if (= n 0)
(stream-car s)
(stream-ref (stream-cdr s) (- n 1))))
(define (add-streams s1 s2)
(stream-map + s1 s2))
(define (scale-stream stream factor)
(stream-map (lambda (x) (* x factor)) stream))
(define (integral delayed-integrand initial-value dt)
(define int
(cons-stream initial-value
(let ((integrand (force delayed-integrand)))
(add-streams (scale-stream integrand dt)
int))))
int)
(define (solve f y0 dt)
(define y (integral (delay dy) y0 dt))
(define dy (stream-map f y))
y)
When I put the definitions above in DrRacket and click Run, no error occurs. However, an error occurs when I try to execute the following line in the interactions window:
(stream-ref (solve (lambda (y) y) 1 0.001) 1000)
The error message is:
mcar: expects argument of type <mutable-pair>; given #<undefined>
When this error occurs, DrRacket highlights the body of the definition of the procedure stream-car, as shown in the picture below:
What is causing this error? I have already used the stream procedures above in previous examples (stream-car, stream-cdr, stream-map, add-streams and scale-stream) and they worked. The integral procedure also works when I use it outside of the solve procedure; for example, if I define (define ones (cons-stream 1 ones)) and then I define (define s (integral (delay ones) 1 1)) and then I execute (stream-ref s 1000), it correctly gives the output 1001.

The error you're reporting is rather weird, I can't see where mcar is being used - or mutable state for that matter. Try this setup, it works for me without using Neil Van Dyke's support language:
#lang racket
(define the-empty-stream '())
(define (stream-null? stream)
(null? stream))
(define-syntax cons-stream
(syntax-rules ()
((cons-stream head tail)
(cons head (delay tail)))))
(define (stream-car stream)
(car stream))
(define (stream-cdr stream)
(force (cdr stream)))
; ... the rest is the same as in your question

Related

Accumulator for infinite streams

I'm trying to implement an accumulator for an infinite stream. I've written the following code but it's running into an infinite loop and failing to terminate
(define (stream-first stream) (car stream))
(define (stream-second stream) (car ((cdr stream))))
(define (stream-third stream) (car ((cdr ((cdr stream))))))
(define (stream-next stream) ((cdr stream)))
(define (stream-foldl func accum stream)
(cond
[(empty? stream) accum]
[else (stream-foldl func (func (stream-first stream) accum) (stream-next stream))] ))
I've written up a few tests to demonstrate what I'm trying to implement
(define (natural-nums)
(define (natural-nums-iter n)
(thunk
(cons n (natural-nums-iter (+ n 1)))))
((natural-nums-iter 0)))
(define x (stream-foldl cons empty (natural-nums)))
(check-equal? (stream-first x) empty)
(check-equal? (stream-second x) (list 0))
(check-equal? (stream-third x) (list 1 0))
(define y (stream-foldl (curry + 1) 10 (naturals)))
(check-equal? (stream-first y) 10)
(check-equal? (stream-second y) 11)
(check-equal? (stream-third y) 13)
Here's a trace of my stream-foldl function
>(stream-foldl
#<procedure:cons>
'()
'(0 . #<procedure:...9/saccum.rkt:25:0>))
()>(stream-foldl
#<procedure:cons>
'(0)
'(1 . #<procedure:...9/saccum.rkt:25:0>))
(0)>(stream-foldl
#<procedure:cons>
'(1 0)
'(2 . #<procedure:...9/saccum.rkt:25:0>))
(1 0)>....
I believe I'm failing to properly set a base case, thus never terminating from the recursion call
Fold is supposed to look at every element in the stream, then produce a result based on those elements. With an infinite stream, it is no surprise that the fold does not terminate (how would you be able to look at every single element in an infinite stream?).
What you can do:
Produce a finite stream out of the infinite stream. stream-take can be used for that. Example implementation of stream-take:
;; Returns a stream containing the first n elements of stream s.
(define (stream-take n s)
(cond ((zero? n) empty-stream)
((empty? s) (error "Stream is shorter than n")
(else
(delay (stream-first s)
(stream-take (- n 1) (stream-rest s)))))))
; Note: 'delay' is the same as the 'thunk' in your code.
Then, fold the finite stream either using your implementation of fold, or stream-fold.

SICP Exercise 2.04

Reading SICP I am now at exercise 2.04, which is a procedural representation of cons, car and cdr, given in the book as follows:
(define (cons x y)
(lambda (m)
(m x y)))
(define (car z)
(z
(lambda (p q)
(p))))
Note, that for running the code I use racket with the following preamble in my code:
#lang racket
(define (Mb-to-B n) (* n 1024 1024))
(define MAX-BYTES (Mb-to-B 64))
(custodian-limit-memory (current-custodian) MAX-BYTES)
I also tried #lang scheme to no avail.
Here is what I understand:
About cons
cons returns a function.
This function which will apply another function given as parameter to the two parameters x and y of cons.
This means by calling cons we retain the possibility to apply a function to the two parameters and are able to treat them as some unit.
About car
car now uses the fact, that we can apply a function to the unit of 2 values given to cons, by giving a function as a parameter to the function, which we get returned from cons.
It supplies that function with a lambda expression, which always returns the first of two given values.
Usage
At first I tried the following:
(car (cons 1 2))
(car (cons 2 3))
(car (cons (cons 1 1) (cons 2 2)))
(car (car (cons (cons 1 1) (cons 2 2))))
However, that leads to errors:
:racket -l errortrace -t exercise-2.04-procedural-representation-of-pairs.rkt
application: not a procedure;
expected a procedure that can be applied to arguments
given: 1
arguments...: [none]
errortrace...:
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt:24:6: (p)
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt:33:0: (car (cons 1 2))
context...:
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt: [running body]
I could not understand what was wrong with my code, so I looked up some usage examples in other people's solutions. One is on http://community.schemewiki.org/?sicp-ex-2.4:
(define x (cons 3 4))
(car x)
But to my surprise, it doesn't work! The solution in the wiki seems to be wrong. I get the following error:
application: not a procedure;
expected a procedure that can be applied to arguments
given: 3
arguments...: [none]
errortrace...:
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt:24:6: (p)
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt:42:0: (car x)
context...:
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt: [running body]
What am I doing wrong here?
You have an error in your code. Instead of:
(define (car z)
(z
(lambda (p q)
(p))))
you should have written (see the book):
(define (car z)
(z
(lambda (p q)
p)))
Note that in the last row p is written without parentheses.
The message: application: not a procedure means that p is not a procedure (it is actually a number), while with the notation (p) you are calling it as a parameterless procedure.

Product of squares of odd elements in list in Scheme

I wanted to write a code in Scheme that writes the square odd elements in list.For example (list 1 2 3 4 5) for this list it should write 225.For this purpose i write this code:
(define (square x)(* x x))
(define (product-of-square-of-odd-elements sequence)
(cond[(odd? (car sequence)) '() (product-of-square-of-odd-elements (cdr sequence))]
[else ((square (car sequence)) (product-of-square-of-odd-elements (cdr sequence)))]))
For run i write this (product-of-square-of-odd-elements (list 1 2 3 4 5))
and i get error like this:
car: contract violation
expected: pair?
given: '()
What should i do to make this code to run properly? Thank you for your answers.
First of all, you need to do proper formatting:
(define (square x) (* x x))
(define (product-of-square-of-odd-elements sequence)
(cond
[(odd? (car sequence))
'() (product-of-square-of-odd-elements (cdr sequence))]
[else
((square (car sequence)) (product-of-square-of-odd-elements (cdr sequence)))]))
Now there are multiple issues with your code:
You are trying to work recursively on a sequence, but you are missing a termination case: What happens when you pass '() - the empty sequence? This is the source of your error: You cannot access the first element of an empty sequence.
You need to build up your result somehow: Currently you're sending a '() into nirvana in the first branch of your cond and put a value into function call position in the second.
So let's start from scratch:
You process a sequence recursively, so you need to handle two cases:
(define (fn seq)
(if (null? seq)
;; termination case
;; recursive case
))
Let's take the recursive case first: You need to compute the square and multiply it with the rest of the squares (that you'll compute next).
(* (if (odd? (car seq)
(square (car seq))
1)
(fn (cdr seq)))
In the termination case you have no value to square. So you just use the unit value of multiplication: 1
This is not a good solution, as you can transform it into a tail recursive form and use higher order functions to abstract the recursion altogether. But I think that's enough for a start.
With transducers:
(define prod-square-odds
(let ((prod-square-odds
((compose (filtering odd?)
(mapping square)) *)))
(lambda (lst)
(foldl prod-square-odds 1 lst))))
(prod-square-odds '(1 2 3 4 5))
; ==> 225
It uses reusable transducers:
(define (mapping procedure)
(lambda (kons)
(lambda (e acc)
(kons (procedure e) acc))))
(define (filtering predicate?)
(lambda (kons)
(lambda (e acc)
(if (predicate? e)
(kons e acc)
acc))))
You can decompose the problem into, for example:
Skip the even elements
Square each element
take the product of the elements
With this, an implementation is naturally expressed using simpler functions (most of which exist in Scheme) as:
(define product-of-square-of-odd-elements (l)
(reduce * 1 (map square (skip-every-n 1 l))))
and then you implement a helper function or two, like skip-every-n.

what am I doing wrong in this scheme stream implementation?

I'm trying to implement streams for an assignment, and I'm missing something important.
This stream-cons should be creating a pair which is a value and a promise for the cdr (to be evaluated later) ..
(define (str1) (stream-cons 1 2))
However, when then I call (stream-car str1) and it complains "contract violation expected: pair?"
I don't understand why str1 is not a valid pair -- what do I do to make this work?
Rob
#lang racket
(define-syntax delay
(syntax-rules () ((delay expr) (lambda () expr))))
(define (force delayed-obj)
(delayed-obj))
(define-syntax stream-cons
(syntax-rules() ((stream-cons x y)
(cons x (delay y)))))
(define (stream-car stream)
(car stream))
(define (stream-cdr stream)
(force (cdr stream)))
(define the-empty-stream '())
;;;
; TESTS
(define (str1) (stream-cons 1 2))
(stream-car str1)
Your line:
(define (str1) (stream-cons 1 2))
is defining a function called str1 and thus str1 is not a pair. It should read:
(define str1 (stream-cons 1 2))

How is the sicp cons-stream implemented?

I'm working through the streams section of the scip and am stuck on how to define a stream.
The following is my code:
(define (memo-func function)
(let ((already-run? false)
(result false))
(lambda ()
(if (not already-run?)
(begin (set! result (function))
(set! already-run? true)
result)
result))))
(define (delay exp)
(memo-func (lambda () exp)))
(define (force function)
(function))
(define the-empty-stream '())
(define (stream-null? stream) (null? stream))
(define (stream-car stream) (car stream))
(define (stream-cdr stream) (force (cdr stream)))
(define (cons-stream a b) (cons a (memo-func (lambda () b))))
If I define integers the way that the book descibes:
(define (integers-starting-from n)
(cons-stream n (integers-starting-from (+ n 1))))
(define integers (integers-starting-from 1))
I get a message saying: Aborting!: maximum recursion depth exceeded.
I'm guessing that the delay function is not working but I don't know how to fix it. I am running the MIT scheme on my Mac.
update 1
So now with cons-stream as a macro, the integers can be defined.
But then I've got another error.
(define (stream-take n s)
(cond ((or (stream-null? s)
(= n 0)) the-empty-stream)
(else (cons-stream (stream-car s)
(stream-take (- n 1) (stream-cdr s))))))
(stream-take 10 integers)
;ERROR - Variable reference to a syntactic keyword: cons-stream
update 2
Please ignore update 1 above
cons-stream needs to be a macro in order for your sample code to work correctly. Otherwise the invocation of cons-stream will evaluate all its arguments eagerly.
Try this (not tested):
(define-syntax cons-stream
(syntax-rules ()
((cons-stream a b)
(cons a (memo-func (lambda () b))))))
P.S. Your delay needs to be a macro also, for similar reasons. Then after you fix delay, you can make your cons-stream use delay directly.
You cannot define delay as a function, since prior to calling it, Scheme will evaluate its argument - which is exactly what you're trying to postpone. SICP says this explicitly that delay should be a special form.

Resources