SICP: Why does process-forget-value call process-new-value? - scheme

This code is from SICP, 3.3.5 Propagation of Constraints. I can't seem to figure out why process-forget-value needs to call process-new-value as the final step.
The text says, "The reason for this last step is that one or more connectors may still have a value (that is, a connector may have had a value that was not originally set by the adder), and these values may need to be propagated back through the adder."
What is the simplest constraint network that can demonstrate why (process-new-value) is needed? Thanks!
(define (adder a1 a2 sum)
(define (process-new-value)
(cond ((and (has-value? a1) (has-value? a2))
(set-value! sum
(+ (get-value a1) (get-value a2))
me))
((and (has-value? a1) (has-value? sum))
(set-value! a2
(- (get-value sum) (get-value a1))
me))
((and (has-value? a2) (has-value? sum))
(set-value! a1
(- (get-value sum) (get-value a2))
me))))
(define (process-forget-value)
(forget-value! sum me)
(forget-value! a1 me)
(forget-value! a2 me)
(process-new-value)) ;;; * WHY * ???
(define (me request)
(cond ((eq? request 'I-have-a-value)
(process-new-value))
((eq? request 'I-lost-my-value)
(process-forget-value))
(else
(error "Unknown request -- ADDER" request))))
(connect a1 me)
(connect a2 me)
(connect sum me)
me)

This Is a test I have made removing process-new-value from the adder. You will see that the behavior is different.
(define c (make-connector))
(define a (make-connector))
(define b (make-connector))
(define d (make-connector))
(constant 10 a)
(constant 10 c)
(constant 10 d)
(define adder1 (adder a b c))
(define adder2 (adder a b d))
> (has-value? b)
#t
> (get-value b)
0
> (forget-value! b adder1)
'done
> (has-value? b)
#f
If you do this with the correct version.
> (has-value? b)
#t
The second time also. As they say, when adder1 tells b to forget its value. a and c being constants will still have a value, and the last process-new-value in adder2, will again set b to 0. This will also work if you use set-value! for a and c.

Related

Is my implementation of SICP Exercise 1.3 going in the right direction?

Exercise 1.3 in SICP asks to define a procedure that takes 3 numbers as arguments and returns the sum of the squares of the 2 largest numbers. I think I've gotten it correct but I wasn't totally sure if I've covered all cases. My implementation is as follows:
(define (bigsq a b c)
(cond ((and (> a b) (> b c)) (+ (* a a) (* b b)))
((and (> a b) (not (> b c))) (+ (* a a) (* c c)))
((> c a) (+ (* b b) (* c c)))
(else (+ (* a a) (* b b))))
Is there a way to write those first 2 conditions as one, as well? Also any comments on efficiency are welcome as well.
For starters, we could use a helper procedure for implementing the sum just once:
(define (sum x y)
(+ (* x x) (* y y)))
Now, for the conditions: given that the order doesn't matter - (sum a b) is the same as (sum b a), there's only 4 cases to consider, and we can avoid repeating some of the comparisons by nesting ifs:
(define (sum-max a b c)
(if (>= a b)
(if (>= b c)
(sum a b)
(sum a c))
(if (>= a c)
(sum b a)
(sum b c))))

Omitting parentheses in cond leads to strange result

Consider the following snippet
(define (f a b c)
(
cond ((and (< b c) (< b a)) (+ c a))
((and (< a c) (< a b)) (+ c b))
((and (< c b) (< c a)) (+ b a))
)
)
(display (f 2 1 3)) ; 5
(newline)
(display (f 2 8 3)) ; 11
(newline)
(display (f 2 8 -3)) ; 10
Now if I comment the second line and second line from bottom
(define (f a b c)
;(
cond ((and (< b c) (< b a)) (+ c a))
((and (< a c) (< a b)) (+ c b))
((and (< c b) (< c a)) (+ b a))
;)
)
The result is
#<undef>
11
10
I could not explain why omitting the parentheses lead to that result. In the second case, I expected thtat the complier would treat cond ((and (< b c) (< b a)) (+ c a)), ((and (< a c) (< a b)) (+ c b)) and ((and (< a c) (< a b)) (+ c b)) as three expressions, the latter two invalid, instead it seems they got executed.
Normally cond keyword should raise an exception when it's interpreted.
But, if your interpreter does not throw any error, you are in the case of block statement, in which the evaluation of the last expression provides the result, the other ones are computed only for side-effects. The code reduces to this:
(define (f a b c) ((and (< c b) (< c a)) (+ b a))))

reverse a general list using scheme

I am trying to reverse a general list using Scheme. How can I reverse a complex list?
I can make a single list like (A B C D) works using my function, but for some complex list inside another list like (F ((E D) C B) A), the result is just (A ((E D) C B) F). How can I improve it?
(define (reverse lst)
(if (null? lst)
lst
(append (reverse (cdr lst)) (list (car lst)))))
Any comments will be much appreciated!
Here is another way that uses a default parameter (r null) instead of the expensive append operation -
(define (reverse-rec a (r null))
(if (null? a)
r
(reverse-rec (cdr a)
(cons (if (list? (car a))
(reverse-rec (car a))
(car a))
r))))
(reverse-rec '(F ((E D) C B) A))
; '(A (B C (D E)) F)
Using a higher-order procedure foldl allows us to encode the same thing without the extra parameter -
(define (reverse-rec a)
(foldl (lambda (x r)
(cons (if (list? x) (reverse-rec x) x)
r))
null
a))
(reverse-rec '(F ((E D) C B) A))
; '(A (B C (D E)) F)
There are several ways of obtaining the expected result. One is to call reverse recursively also on the car of the list that we are reversing, of course taking care of the cases in which we must terminate the recursion:
(define (reverse x)
(cond ((null? x) '())
((not (list? x)) x)
(else (append (reverse (cdr x)) (list (reverse (car x)))))))
(reverse '(F ((E D) C B) A))
'(A (B C (D E)) F)
(A ((E D) C B) F) is the correct result, if your goal is to reverse the input list. There were three elements in the input list, and now the same three elements are present, in reverse order. Since it is correct, I don't suggest you improve its behavior!
If you have some other goal in mind, some sort of deep reversal, you would do well to specify more clearly what result you want, and perhaps a solution will be easier to find then.

Scheme function won't print

Please tell me why the following Scheme function won't print the result. I'm using DrRacket.
#lang sicp
(define (sqr x) (* x x))
(define (sum_of_greatest_squares a b c)
(if(> a b)
(if(> a c)
(if(> b c)
((+ (sqr a) (sqr c))(+ (sqr a) (sqr b))))
(+ (sqr a) (sqr c))
)
(if(> b c)
(if (> a c)
((+ (sqr a) (sqr b))(+ (sqr b) (sqr c)))
(+ (sqr c) (sqr b))))
))
(sum_of_greatest_squares 3 4 5)
Its plain to see that you haven't been very detail-oriented with your learning. Your code contains countless mistakes and you've allowed yourself to bring habits from other languages into your learning of scheme. DrRacket clearly shows there's a syntax error with your program, so that's a good place to start.
The sections I have bolded are missing an else expression
(define (sum_of_greatest_squares a b c)
(if(> a b)
(if(> a c)
(if(> b c)
((+ (sqr a) (sqr c))(+ (sqr a) (sqr b))))
(+ (sqr a) (sqr c))
)
(if(> b c)
(if (> a c)
((+ (sqr a) (sqr b))(+ (sqr b) (sqr c)))
(+ (sqr c) (sqr b))))
))
The formatting of your code is bad and thus makes it harder to see where mistakes were made.
Moving along, here's another big mistake
((+ (sqr a) (sqr c))(+ (sqr a) (sqr b)))
You can't just put () wherever you want, like you can in some languages. () are used for procedure application in Lisp/Scheme/Racket.
Say a = 1, b = 2, and c = 3, the above line would be the equivalent of
((+ (sqr 1) (sqr 3))(+ (sqr 1) (sqr 2)))
((+ 1 9 )(+ 1 4 ))
(10 5)
The last line is (10 5) which says "apply the number 5 to the number 10" – which makes no sense.
You make the same mistake later in the code too. Try fixing up these problems first and then update your question.
ps: don't use snake_case names like sum_of_greatest_squares. Schemers typically would format that as sum-of-greatest-squares.
It's not immediately clear what your procedure is supposed to do anyway. My guess is that it's supposed to square the two largest inputs and then sum them.
You could do a huge hierarchy of if expressions to decide which two arguments to perform a computation with... but another way would be to always use the same two arguments to compute the result, but use if expressions to move the appropriate arguments into the correct place.
Consider this as a lateral alternative to your procedure
(define (sqr x) (* x x))
(define (sum-of-greatest-squares a b c)
(cond ((< a b) (sum-of-greatest-squares b c a))
((< b c) (sum-of-greatest-squares a c b))
(else (+ (sqr a) (sqr b)))))
This will always sum the squares of the two greatest numbers, but does so in a much cleaner way
Lastly, Jörg mentions that you're not actually printing anything anywhere. I know you mean to imply that DrRacket isn't showing the result of your program in the Interactions window. However, if you do want to explicitly print to the console, look at the display* and print* procedures

Scheme quadratic function/square root check

Im want to make a function where rootcheck has a list L as input, L always is 3 atoms (a b c) where a is coefficient of x^2, b coef of x and c is the constant. it checks if the equation is quadratic, using discriminant (b^2 - 4ac) and should output this (num 'L) where num is the number of roots and L is a list that contains the roots themselves (using quadratic formula), L is empty in case of no roots. here is my code:
(define roots-2
(lambda (L)
(let ((d (- (* (cdr L) (cdr L)) (4 (car L) (caddr L))))))
(cond ((< d 0) (cons(0 null)))
((= d 0) (cons(1 null)))
(else((> d 0) (cons(2 null)))))
))
its giving me no expression in body error.
also I tried to code the quadratic function and even tried some that are online, one compiled fint but gave me an error when I inserted input this is the code for the quadratic function, NOT MINE!
(define quadratic-solutions
(lambda (a b c) (list (root1 a b c) (root2 a b c))))
(define root1
(lambda (a b c) (/ (+ (- b) (sqrt (discriminant a b c)))
(* 2 a))))
(define root2
(lambda (a b c) (/ (- (- b) (sqrt (discriminant a b c)))
(*2 a))))
(define discriminant
(lambda (a b c) (- (square b) (* 4 (* a c)))))
There are several mistakes in the code:
Some parentheses are incorrectly placed, use a good IDE to detect such problems. This is causing the error reported, the let doesn't have a body
You forgot to multiply in the 4ac part
You're incorrectly accessing the second element in the list
The else part must not have a condition
The output list is not correctly constructed
This should fix the errors, now replace null with the actual call to the function that calculates the roots for the second and third cases (the (< d 0) case is fine as it is):
(define roots-2
(lambda (L)
(let ((d (- (* (cadr L) (cadr L)) (* 4 (car L) (caddr L)))))
(cond ((< d 0) (list 0 null))
((= d 0) (list 1 null))
(else (list 2 null))))))
for the quadractic function part, I found a code online and tweaked it to provide both roots of a quadratic equation. returns a list of both roots
(define (solve-quadratic-equation a b c)
(define disc (sqrt (- (* b b)
(* 4.0 a c))))
(list (/ (+ (- b) disc) (* 2.0 a))
(/ (- (- b) disc) (* 2.0 a))
))

Resources