How is the sicp cons-stream implemented? - scheme

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.

Related

Why does this expression evaluate to 4 (call/cc)

Sorry this simple continuation example evaluates to 4, but I could not figure out why:
(call/cc
(lambda (k)
(* 5 (k 4))))
Chez Scheme 9.5.3
call/cc lets you get the advantages of continuation passing style without having to write it in continuation passing style. eg.
(define (cars lsts)
(define (cars lsts k)
(cond ((null? lsts) (k '()))
((null? (car lsts)) '())
(else (cars (cdr lsts)
(lambda (r)
(k (cons (caar lsts) r)))))))
(cars lsts values))
;; eg
(cars '()) ; ==> ()
(cars '((1) (2) (3))) ; ==> (1 2 3)
(cars '((1) (2) ())) ; ==> ()
Can be written like this:
(define (cars lsts)
(call/cc
(lambda (bail)
(define (cars lsts)
(cond ((null? lsts) '())
((null? (car lsts)) (bail '()))
(else (cons (caar lsts) (cars (cdr lsts))))))
(cars lsts))))
call/cc& looks like this in CPS:
(define (call/cc& proc k)
(define (exit& v ignored-k)
(k v))
(proc exit& k))
And your simple example can easily be rewritten to continuation passing style:
(call/cc& (lambda (k& real-k)
(k& 4 (lambda (res)
(*& 5 res real-k))))
display)
So looking at that the ignore-k gets ignored and 4 gets passed to the continuation of call/cc& which I have put display which then displays 4 in the repl.
I would explain you by writing a code with the same semantics by using CPS.
((lambda (k)
(k 4
(lambda (v)
(* 5 v))))
(lambda (result stack)
;; this continuation will drop the stack
result))
After you call the continuation K, you also call it using the remained stack, but the stack is dropped.
Had you took into account the remaining stack you would have had:
((lambda (k)
(k 4
(lambda (v)
(* 5 v))))
(lambda (result stack)
;; this continuation will consider the stacked computation
(stack result)))
and in this case the result would have been 20.
But in the semantics from your code, by calling the continuation, you dropped the stack, the not-finished computation.
The continuation will return with the value passed to it (k 4), so 4 is the return value.

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

Running code from SICP section 3.5.4 with DrRacket

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

programmatic way to stop a function after certain time and debug enclosed variables

A long-run function like infinite loop:
> (define appendInf
(lambda (lst)
(appendInf (cons 1 lst)))
In Chez Scheme, make-engine can achieve the stopping after ticks:
> (define eng
(make-engine
(lambda ()
(appendInf '()))))
While of course with the scope of lst I get error when:
> (eng 50
list
(lambda (new-eng)
(set! eng new-eng)
(length lst)))
Exception: variable lst is not bound
If I want to get the value 'lst' in appendInf when the time limit is reached, I use set!:
> (define lst '())
> (define appendInf
(lambda (ls)
(set! lst (cons 1 ls))
(appendInf lst)))
now I can get:
> (eng 50
list
(lambda (new-eng)
(set! eng new-eng)
(length lst)))
8
So for every variable within the function I want to trace, a global variable needs to be added, and one more transforming by adding (set!…).
is this a correct way to handle any enclosed variables?
if yes to 1, in Scheme is there a better way to achieve this?
is there any programming language that can more easily
implement this kind of debugging?
Well. I'm using racket and it has a pretty good debugger and does standard r6rs as well as non-standard racket.
;; macro to do the heavy work
(define-syntax recdb
(syntax-rules ()
((_ thunk fun a1 ...)
(let ((orig-fun fun)(ethunk thunk))
(fluid-let ((fun (lambda args
(if (ethunk)
(apply orig-fun args) ;; set breakpoint on this
(apply orig-fun args)))))
(fun a1 ...))))))
;; a time-thunk generator
(define (period-sec sec)
(let ((time-done (+ sec (current-seconds))))
(lambda ()
(if (< time-done (current-seconds))
(begin
(set! time-done (+ sec (current-seconds)))
#t)
#f))))
;; a round-thunk generator
(define (rounds n)
(let ((rounds-to-go n))
(lambda ()
(if (zero? rounds-to-go)
(begin
(set! rounds-to-go (- n 1))
#t)
(begin
(set! rounds-to-go (- rounds-to-go 1))
#f)))))
;; my never ending procedure
(define (always n)
(always (+ n 1)))
;; one of the ones below to implement
(recdb (rounds 10) always 0))
(recdb (period-sec 1) always 0)
;; functions with auxillary procedures need to have their gut changed for it to work
(define (fib n)
(define (fib-aux n a b)
(if (= n 0)
a
(fib-aux (- n 1) b (+ a b))))
(recdb (period-sec 2) fib-aux n 0 1))
;; trying it
(fib 200000)
Now. Just run the debugger and set breakpoint (right click expression in the macro and choose "Pause at this point") where it's indicated in the code and you have a way to examine the variables every x seconds or x times.
Happy debugging :)

Resources