SICP exercise 1.15 Is operands evaluated prior to operators? - scheme

You can see the question here
The code used is
(define (cube x) (* x x x))
(define (p x) (- (* 3 x) (* 4 (cube x))))
(define (sine angle)
(if (not (> (abs angle) 0.1))
angle
(p (sine (/ angle 3.0)))))
So I understand what the code is doing, but I have a question on part a. How many times is the procedure p applied when (sine 12.15) is evaluated?
I googled and most answers look like this:
(sine 12.15)
(p (sine 4.05))
(p (p (sine 1.35)))
(p (p (p (sine 0.45))))
(p (p (p (p (sine 0.15)))))
(p (p (p (p (p (sine 0.05))))))
(p (p (p (p (p 0.05)))))
I also understand what the answers are saying, but my question is, why is the procedure p not evaluated first? More specifically, when the interpreter reaches the second line, (p(sine 4.05)), why doesn't it first evaluate as (- (* 3 (sine 4.05)) (* 4 (cube (sine 4.05)))) and take this result to do the recursion?
This is definitely a messier approach, and I believe the answer to my question comes down to how "Applicative Order" is performed. Does this question suggest that when evaluating, the interpreter will first evaluate the operands, then the operators?

Imagine this form:
(+ 1 2 (- 3 1))
In applicative order, since there are no special forms involved all the 4 parts, the variable +, the form (- 3 1), and the two constants 1 and 2 needs to be evaluated before whatever is the result of evaluating + can be applied.
The order of evaluation is deliberately left out of the language and thus the implementation can decide what is the best order for each call place. In reality most scheme implementations does a left to right. I think MIT Scheme does a strict right to left. The only time you actually notice this is if any of the expressions in a form has side effects.
So if we look at your form:
(p (sine 4.05))
What must be finished evaluated before (p ...) can be applied? Well (sine 4.05) of course. Also notice that in your naive expansion of p first you actually duplicated (sine 4.05) which would have complicated your further expansion quite a bit. In lazy languages the expression isn't copied but simply replaced with a promise that would remember the calculated value once computed.

The variable p might well be evaluated first. Since
(define (p x) (- (* 3 x) (* 4 (cube x))))
is the same as
(define p
(lambda (x) (- (* 3 x) (* 4 (cube x)))))
evaluating p produces the value of the lambda form, which is the function to be called.
Then when the argument's value is also found, that procedure is applied to that argument value, and at that point the procedure's body is entered:
((lambda (x) (- (* 3 x) (* 4 (cube x))))
(sine 4.05))
=
(- (* 3 <s405>) (* 4 (cube <s405>)))
=
...
where <s405> indicates the actual value of (sine 4.05), calculated recursively.

Related

Scheme: Proabably a typo in SICP. 1.3.2. Am I right?

In SICP, (1.3.2. page: 62), there is a solution for finding pi-sum using lambda. The solution is:
(define (pi-sum a b)
(sum (lambda (x) (/ 1.0 (* x (+ x 2))))
a
(lambda (x) (+ x 4))
b))
However, I feel there should be a bracket enclosing ((lambda (x) (+ x 4) b). The program as such produces an error saying sum is expecting a number but getting a procedure.
Modifying the above code is giving no error.
(define (pi-sum a b)
(sum ((lambda (x) (/ 1.0 (* x (+ x 2))))
a)
((lambda (x) (+ x 4))
b)))
Please correct me if my understanding is wrong. I assume the book cannot be wrong.
The pi-sum procedure in the book is making use of the higher-order procedure sum, defined earlier in 1.3.1. The sum procedure takes a and b as arguments which describe the bounds of the summation, and it takes term and next as arguments which describe how to create a term from a, and how to get the next a from the current a. Both term and next need to be procedures. Here is the definition of sum from the book:
(define (sum term a next b)
(if (> a b)
0
(+ (term a)
(sum term (next a) next b))))
If you add parentheses in the definition of pi-sum, you should get an exception because sum requires four arguments, but now only two are passed. I am not sure why you are getting an error like "sum is expecting a number but getting a procedure", but I suspect that you have a different definition for sum than the one intended by the book.

Make procedure in Scheme by lambda

I am learning Scheme by 'Structure and Interpretation of Computer Programs'
In Chapter 1.3.2 Constructing Procedures Using lambda.
I understood lambda like this.
The value to match the lambda is written outside the parenthesis of the lambda.
((lambda (x) (+ x 4) 4) ; (x) is matched to 4, result is 8
But in SICP, another example code is different.
The code is :
(define (sum x y) (+ x y))
(define (pi-sum a b)
(sum (lambda (x) (/ 1.0 (* x (+ x 3))))
a
(lambda (x) (+ x 4))
b
))
(pi-sum 3 6)
I think if (lambda (x) (/ 1.0 (* x (+ x 3)))) want match to a, lambda and a must bound by parenthesis.
But in example code, don't use parenthesis.
When I run this code, error is occurs.
error is this :
***'sum: expects only 2 arguments, but found 4'***
When I use more parenthesis like this :
(define (sum x y) (+ x y))
(define (pi-sum a b)
(sum ((lambda (x) (/ 1.0 (* x (+ x 3))))
a)
((lambda (x) (+ x 4))
b)
))
(pi-sum 2 6) ; result is 10.1
Code is run.
I'm confused because of SICP's example code.
Am I right on the principle of lambda?
If I am right, why SICP write like that?
It says to use the sum from 1.3.1. On page 77 (actually starting on 77 and ending on 78) it looks like this:
(define (sum term a next b)
(if (> a b)
0
(+ (term a)
(sum term (next a) next b))))
As you can see it looks a lot different from your sum that just adds two number together. You also had a typo in pi-sum:
(define (pi-sum a b)
(sum (lambda (x) (/ 1.0 (* x (+ x 2)))) ; multiplied by 2, not 3!
a
(lambda (x) (+ x 4))
b))
(* 8 (pi-sum 1 1000))
; ==> 3.139592655589783
So the point here is that you can pass lambdas instead of named procedures. Since (define (name . args) body ...) is just syntax sugar for (define name (lambda args body ...)) passing (lambda args body ...) instead of defining it and pass a name is just an equal refactoring.
Parentheses around a variable (+) or a lambda ((lambda args body ...)) calls whatever procedure the operator expression evaluates. It is not what you want since you pass procedures to be used by sum as an abstraction. sum can do multiplications or any number of things based on what you pass. in sum term is the procedure (lambda (x) (/ 1.0 (* x (+ x 2)))) and you see it calls it as apart of its code.

I'm trying to figure out how to incorporate 3 variables into my tail recursion code for racket

Write a tail recursive function called popadd that models a population with P people at time t = 0 and adds d people per year.
(define (popadd t P)
(if (= t 0)
P
(+(popadd( - t 1) P)d))
)
but, of course, I get the error that d hasn't been defined yet, which is true. I tried adding it as an input, but as a return I get the number inserted for D.
You can simply pass along another parameter to the recursion:
(define (popadd t P d)
(if (= t 0)
P
(+ d (popadd (- t 1) P d))))
Or you can define the value, to avoid passing it around - assuming it doesn't need to change:
(define d 100)
(define (popadd t P)
(if (= t 0)
P
(+ d (popadd (- t 1) P))))
Notice that you could do the same with P, if it's ok. It really depends on what's the expected contract for the procedure.
Note that neither your code nor the code in the other answer is tail-recursive: in a recursive call like (+ (f ...)), f is not in tail position. To make the code tail-recursive you need the result of the recursive call be the result of the overall call (so in the above example, + is in tail position). To do this you need an auxiliary function. Here is a way of doing it which relies only on local define:
(define (popadd t P d)
(define (popadd-loop tau pop)
(if (zero? tau)
pop
(popadd-loop (- tau 1) (+ pop d))))
(popadd-loop t P))
Here is essentially the same thing using named-let, which is nicer:
(define (popadd t P d)
(let popadd-loop ([tau t] [pop P])
(if (zero? tau)
pop
(popadd-loop (- tau 1) (+ pop d)))))
Finally note that this problem has a closed-form solution:
(define (popadd t P d)
(+ P (* t d)))
I really wish that people trying to teach programming knew enough maths to not set problems which have trivial closed-form answers, as doing so encourages people to write inefficient (in the complexity-class sense) code. Obviously this is not your fault: it's your teacher's.

What am I doing wrong with Scheme?

When I enter the following:
(define (root a b c)
(/ (+ (-b) (sqrt (- (exp b 2) (* 4 a c)))) (* 2 a)))
and then enter:
(root 3 6 2)
I get a message indicating that the procedure had two arguments but only requires exactly one. What am I doing wrong?
The exp function doesn't do exponents really, it does something else mathy. (I don't know.)
What you want is usually called pow for "power" but probably isn't defined in your environment, so I suggest you just define your own square method:
(define (square x) (* x x))
And then:
(define (root a b c)
(/ (+ (- b) (sqrt (- (square b) (* 4 a c)))) (* 2 a)))
Edit: Oh, you'll also have to change a couple spacing issues, like (* 4 a c) instead of (*4 a c), and (- b) instead of (-b). You always have to separate the operator from the operands with spaces.
The procedure exp raises the number e to the power of its argument, if you need to raise an argument to the power of another argument, use expt. Even better, given that you only need to square b, a simple multiplication will do. Like this:
(define (root a b c)
(/ (+ (- b) (sqrt (- (* b b) (* 4 a c))))
(* 2 a)))
The function the error refers to is exp which takes only one argument. The exp function calculates the exponential function, not an exponent. You want expt, which raises a root x to the exponent y:
(expt b 2)
You can also just multiply the number times itself.
I usually keep R5RS or The Scheme Programming Language on hand since these basic functions can be hard to keep straight.

SICP exercise 1.16, where is my bug, because it looks right to me

I've just started working through this book for fun; I wish it were homework, but I could never afford to attend MIT, and there are tons of people smarter than me anyway. :p
fast-exp is supposed to find b^n, i.e. 4^2 = 16, 3^3 = 27
(define (fast-exp b n)
(define (fast-exp-iter n-prime a)
(cond ((= n-prime 1) a)
((= (remainder n-prime 2) 1) (fast-exp-iter (- n-prime 1) (* a b)))
(else (fast-exp-iter (/ n-prime 2) (* a b b)))))
(fast-exp-iter n 1))
fast-exp 4 2; Expected 16, Actual 2
You forgot to call fast-exp. Instead, you evaluated three separate atoms. To actually evaluate the fast-exp of 4 to the 2, you'd have to write
(fast-exp 4 2)
The solution you have written here is also incorrect. e.g. Check out (fast-exp 2 6). Expected: 64, actual: 32.
Your solution is calculating wrong answers. (See http://ideone.com/quT6A) In fact, how you in principle can write a tail-recursive fast exponentiation passing only two numbers as arguments? I don't think it's even possible, because in the middle of computation you don't know what multiplier to use if you encounter odd exponent.
But I can give an example of working solution that is exactly what is expected by SICP authors (iterative process using "invariant quantity" (a * b^n), where a is initially 1)
(define (pow x y)
(define (powi acc x y)
(cond
((= y 0) acc)
((odd? y) (powi (* acc x) x (- y 1)))
(else (powi acc (* x x) (/ y 2)))))
(powi 1 x y))

Resources