SICP 1.45 - Why are these two higher order functions not equivalent? - scheme

I'm going through the exercises in [SICP][1] and am wondering if someone can explain the difference between these two seemingly equivalent functions that are giving different results! Is this because of rounding?? I'm thinking the order of functions shouldn't matter here but somehow it does? Can someone explain what's going on here and why it's different?
Details:
Exercise 1.45: ..saw that finding a fixed point of y => x/y does not
converge, and that this can be fixed by average damping. The same
method works for finding cube roots as fixed points of the
average-damped y => x/y^2. Unfortunately, the process does not work
for fourth roots—a single average damp is not enough to make a
fixed-point search for y => x/y^3 converge.
On the other hand, if we
average damp twice (i.e., use the average damp of the average damp of
y => x/y^3) the fixed-point search does converge. Do some experiments
to determine how many average damps are required to compute nth roots
as a fixed-point search based upon repeated average damping of y => x/y^(n-1).
Use this to implement a simple procedure for computing the roots
using fixed-point, average-damp, and the repeated procedure
of Exercise 1.43. Assume that any arithmetic operations you need are
available as primitives.
My answer (note order of repeat and average-damping):
(define (nth-root-me x n num-repetitions)
(fixed-point (repeat (average-damping (lambda (y)
(/ x (expt y (- n 1)))))
num-repetitions)
1.0))
I see an alternate web solution where repeat is called directly on average damp and then that function is called with the argument
(define (nth-root-web-solution x n num-repetitions)
(fixed-point
((repeat average-damping num-repetition)
(lambda (y) (/ x (expt y (- n 1)))))
1.0))
Now calling both of these, there seems to be a difference in the answers and I can't understand why! My understanding is the order of the functions shouldn't affect the output (they're associative right?), but clearly it is!
> (nth-root-me 10000 4 2)
>
> 10.050110705350287
>
> (nth-root-web-solution 10000 4 2)
>
> 10.0
I did more tests and it's always like this, my answer is close, but the other answer is almost always closer! Can someone explain what's going on? Why aren't these equivalent? My guess is the order of calling these functions is messing with it but they seem associative to me.
For example:
(repeat (average-damping (lambda (y) (/ x (expt y (- n 1)))))
num-repetitions)
vs
((repeat average-damping num-repetition)
(lambda (y) (/ x (expt y (- n 1)))))
Other Helper functions:
(define (fixed-point f first-guess)
(define (close-enough? v1 v2)
(< (abs (- v1 v2))
tolerance))
(let ((next-guess (f first-guess)))
(if (close-enough? next-guess first-guess)
next-guess
(fixed-point f next-guess))))
(define (average-damping f)
(lambda (x) (average x (f x))))
(define (repeat f k)
(define (repeat-helper f k acc)
(if (<= k 1)
acc
;; compose the original function with the modified one
(repeat-helper f (- k 1) (compose f acc))))
(repeat-helper f k f))
(define (compose f g)
(lambda (x)
(f (g x))))

You are asking why “two seemingly equivalent functions” produce a different result, but the two functions are in effect very different.
Let’s try to simplify the problem to see why they are different. The only difference between the two functions are the two expressions:
(repeat (average-damping (lambda (y) (/ x (expt y (- n 1)))))
num-repetitions)
((repeat average-damping num-repetition)
(lambda (y) (/ x (expt y (- n 1)))))
In order to simplify our discussion, we assume num-repetition equal to 2, and a simpler function then that lambda, for instance the following function:
(define (succ x) (+ x 1))
So the two different parts are now:
(repeat (average-damping succ) 2)
and
((repeat average-damping 2) succ)
Now, for the first expression, (average-damping succ) returns a numeric function that calculates the average between a parameter and its successor:
(define h (average-damping succ))
(h 3) ; => (3 + succ(3))/2 = (3 + 4)/2 = 3.5
So, the expression (repeat (average-damping succ) 2) is equivalent to:
(lambda (x) ((compose h h) x)
which is equivalent to:
(lambda (x) (h (h x))
Again, this is a numeric function and if we apply this function to 3, we have:
((lambda (x) (h (h x)) 3) ; => (h 3.5) => (3.5 + 4.5)/2 = 4
In the second case, instead, we have (repeat average-damping 2) that produces a completely different function:
(lambda (x) ((compose average-damping average-damping) x)
which is equivalent to:
(lambda (x) (average-damping (average-damping x)))
You can see that the result this time is a high-level function, not an integer one, that takes a function x and applies two times the average-damping function to it. Let’s verify this by applying this function to succ and then applying the result to the number 3:
(define g ((lambda (x) (average-damping (average-damping x))) succ))
(g 3) ; => 3.25
The difference in the result is not due to numeric approximation, but to a different computation: first (average-damping succ) returns the function h, which computes the average between the parameter and its successor; then (average-damping h) returns a new function that computes the average between the parameter and the result of the function h. Such a function, if passed a number like 3, first calculates the average between 3 and 4, which is 3.5, then calculates the average between 3 (again the parameter), and 3.5 (the previous result), producing 3.25.

The definition of repeat entails
((repeat f k) x) = (f (f (f (... (f x) ...))))
; 1 2 3 k
with k nested calls to f in total. Let's write this as
= ((f^k) x)
and also define
(define (foo n) (lambda (y) (/ x (expt y (- n 1)))))
; ((foo n) y) = (/ x (expt y (- n 1)))
Then we have
(nth-root-you x n k) = (fixed-point ((average-damping (foo n))^k) 1.0)
(nth-root-web x n k) = (fixed-point ((average-damping^k) (foo n)) 1.0)
So your version makes k steps with the once-average-damped (foo n) function on each iteration step performed by fixed-point; the web's uses the k-times-average-damped (foo n) as its iteration step. Notice that no matter how many times it is used, a once-average-damped function is still average-damped only once, and using it several times is probably only going to exacerbate a problem, not solve it.
For k == 1 the two resulting iteration step functions are of course equivalent.
In your case k == 2, and so
(your-step y) = ((average-damping (foo n))
((average-damping (foo n)) y)) ; and,
(web-step y) = ((average-damping (average-damping (foo n))) y)
Since
((average-damping f) y) = (average y (f y))
we have
(your-step y) = ((average-damping (foo n))
(average y ((foo n) y)))
= (let ((z (average y ((foo n) y))))
(average z ((foo n) z)))
(web-step y) = (average y ((average-damping (foo n)) y))
= (average y (average y ((foo n) y)))
= (+ (* 0.5 y) (* 0.5 (average y ((foo n) y))))
= (+ (* 0.75 y) (* 0.25 ((foo n) y)))
;; and in general:
;; = (2^k-1)/2^k * y + 1/2^k * ((foo n) y)
The difference is clear. Average damping is used to dampen the possibly erratic jumps of (foo n) at certain ys, and the higher the k the stronger the damping effect, as is clearly seen from the last formula.

Related

In MIT Scheme/Racket, can a value be both the operator and operand? i.e. (lambda (y) (y y))

For the function foo6, give a Curried application of the procedure which evaluates to 3.
(define foo6
(lambda (x)
(x (lambda (y) (y y)))))
I've defined a foo7 to see how the last line works
(define foo7 (lambda (y) (y y)))
Is there some "y" that can both be the operator and the operand?
Edit: The question should read:
Is there some "y" that can both be the operator and the operand that will not cause an error or infinite loop?
Question taken from the Structure and Interpretation of Computer Program (SICP) Sample Programming assignments:
https://mitpress.mit.edu/sicp/psets/index.html
From the "Introductory assignment," Exercise 11:
PDF Version: https://github.com/yangchenyun/learning-sicp/raw/master/practices/assignments/01.introductory-assignment/ps1_1.pdf
PS (Original Version):
https://mitpress.mit.edu/sicp/psets/ps1/ps1_1.ps
Yes. Scheme and Racket are both Lisp1s which means they only have one namespace and thus. the variable v can be any value including procedures.
The second you see something like (lambda (y) (y y)) it obvious what type y is a procedure by the way it is being applied. For any other values than a procedure it would end with a application error:
((lambda (y) (y y)) 5)
; ERROR: application: 5 is not a procedure
The procedure itself will probably expect itself as an argument so we can assume some sort of omega or z combinator.
We have higher order procedures you pass functions as values in operand position and to use them just put then in operator position:
(define (times n p)
(lambda (arg)
(let loop ((n n) (acc arg))
(if (<= n 0)
acc
(loop (sub1 n) (p acc))))))
(define double (lambda (v) (+ v v)))
(define test (times 3 double))
(test 5) ; ==> 40
Scheme is not alone on having this feature. The same code as above can be expressed just as easily in JavaScript as it also only have one namespace and parseInt(x) evaluates the variable parseInt to a value that gets applied with the argument you get from evaluating the variable x. They are just two variables, nothing special.
EDIT
Here is an example where (lambda (y) (y y)) is used in something usefull.
;; the Z combinator
(define Z
(lambda (f)
((lambda (y)
(y y))
(lambda (g)
(f (lambda args (apply (g g) args)))))))
(define (fib n)
((Z (lambda (helper)
(lambda (n a b)
(if (zero? n)
a
(helper (- n 1) b (+ a b))))))
n 0 1))
(fib 10) ; ==> 55
The Z combinator is the Y combinator for eager languages. It makes it possibly for self reference without mutating the environment.
Yes,
(define (foobar n)
((foo6
(lambda (u) (u (lambda (y)
(lambda (n)
(if (zero? n)
1
(* n ((y y) (- n 1)))))))))
n))
Y? I mean, why? Because
(foo6 x)
=
(x (lambda (y) (y y))
=
(x u) where u = (lambda (y) (y y))
i.e. (u y) = (y y)
So the argument to foo6 should be a function x expecting u such that u y = y y. So we give it the function such that
(foobar n)
=
((foo6 x) n)
=
((x u) n)
=
((u y) n) so, x = (lambda (u) (u (lambda (y) (lambda (n) ...))))
=
((y y) n) so, y = (lambda (y) (lambda (n) ...))
=
((lambda (n)
(if (zero? n)
1
(* n ((y y) (- n 1)))))
n)
and later, when / if ((y y) (- n 1)) needs to be evaluated, the same (lambda (n) ...) function is arrived at again as the result of (y y) application, and is used again when / if ((y y) (- (- n 1) 1)) needs to be evaluated.
Try it! What's (foobar 5) evaluating to? (ʎʇuǝʍʇpuɐpǝɹpunɥǝuo)
So, everything fits. Do u see y?
(lambda (y) (y y)) actually has a name: it is "U combinator".

Returning the sum of positive squares

I'm trying to edit the current program I have
(define (sumofnumber n)
(if (= n 0)
1
(+ n (sumofnumber (modulo n 2 )))))
so that it returns the sum of an n number of positive squares. For example if you inputted in 3 the program would do 1+4+9 to get 14. I have tried using modulo and other methods but it always goes into an infinite loop.
The base case is incorrect (the square of zero is zero), and so is the recursive step (why are you taking the modulo?) and the actual operation (where are you squaring the value?). This is how the procedure should look like:
(define (sum-of-squares n)
(if (= n 0)
0
(+ (* n n)
(sum-of-squares (- n 1)))))
A definition using composition rather than recursion. Read the comments from bottom to top for the procedural logic:
(define (sum-of-squares n)
(foldl + ; sum the list
0
(map (lambda(x)(* x x)) ; square each number in list
(map (lambda(x)(+ x 1)) ; correct for range yielding 0...(n - 1)
(range n))))) ; get a list of numbers bounded by n
I provide this because you are well on your way to understanding the idiom of recursion. Composition is another of Racket's idioms worth exploring and often covered after recursion in educational contexts.
Sometimes I find composition easier to apply to a problem than recursion. Other times, I don't.
You're not squaring anything, so there's no reason to expect that to be a sum of squares.
Write down how you got 1 + 4 + 9 with n = 3 (^ is exponentiation):
1^2 + 2^2 + 3^2
This is
(sum-of-squares 2) + 3^2
or
(sum-of-squares (- 3 1)) + 3^2
that is,
(sum-of-squares (- n 1)) + n^2
Notice that modulo does not occur anywhere, nor do you add n to anything.
(And the square of 0 is 0 , not 1.)
You can break the problem into small chunks.
1. Create a list of numbers from 1 to n
2. Map a square function over list to square each number
3. Apply + to add all the numbers in squared list
(define (sum-of-number n)
(apply + (map (lambda (x) (* x x)) (sequence->list (in-range 1 (+ n 1))))))
> (sum-of-number 3)
14
This is the perfect opportunity for using the transducers technique.
Calculating the sum of a list is a fold. Map and filter are folds, too. Composing several folds together in a nested fashion, as in (sum...(filter...(map...sqr...))), leads to multiple (here, three) list traversals.
But when the nested folds are fused, their reducing functions combine in a nested fashion, giving us a one-traversal fold instead, with the one combined reducer function:
(define (((mapping f) kons) x acc) (kons (f x) acc)) ; the "mapping" transducer
(define (((filtering p) kons) x acc) (if (p x) (kons x acc) acc)) ; the "filtering" one
(define (sum-of-positive-squares n)
(foldl ((compose (mapping sqr) ; ((mapping sqr)
(filtering (lambda (x) (> x 0)))) ; ((filtering {> _ 0})
+) 0 (range (+ 1 n)))) ; +))
; > (sum-of-positive-squares 3)
; 14
Of course ((compose f g) x) is the same as (f (g x)). The combined / "composed" (pun intended) reducer function is created just by substituting the arguments into the definitions, as
((mapping sqr) ((filtering {> _ 0}) +))
=
( (lambda (kons)
(lambda (x acc) (kons (sqr x) acc)))
((filtering {> _ 0}) +))
=
(lambda (x acc)
( ((filtering {> _ 0}) +)
(sqr x) acc))
=
(lambda (x acc)
( ( (lambda (kons)
(lambda (x acc) (if ({> _ 0} x) (kons x acc) acc)))
+)
(sqr x) acc))
=
(lambda (x acc)
( (lambda (x acc) (if (> x 0) (+ x acc) acc))
(sqr x) acc))
=
(lambda (x acc)
(let ([x (sqr x)] [acc acc])
(if (> x 0) (+ x acc) acc)))
which looks almost as something a programmer would write. As an exercise,
((filtering {> _ 0}) ((mapping sqr) +))
=
( (lambda (kons)
(lambda (x acc) (if ({> _ 0} x) (kons x acc) acc)))
((mapping sqr) +))
=
(lambda (x acc)
(if (> x 0) (((mapping sqr) +) x acc) acc))
=
(lambda (x acc)
(if (> x 0) (+ (sqr x) acc) acc))
So instead of writing the fused reducer function definitions ourselves, which as every human activity is error-prone, we can compose these reducer functions from more atomic "transformations" nay transducers.
Works in DrRacket.

SICP Exercise 2.5 - selector behaves inconstantly

I'm reading SICP and doing exercise 2.5:
Exercise 2.5. Show that we can represent pairs of nonnegative
integers using only numbers and arithmetic operations if we represent
the pair a and b as the integer that is the product 2^a*3^b.
Give the corresponding definitions of the procedures cons, car,
and cdr.
Here is my solution:
;;; Exercise 2.5
;;; ============
(define (cons x y)
(* (expt 2 x)
(expt 3 y)))
(define (car z)
; n is a power of 2, which is greater than z
(let ((n (expt 2 (ceiling (/ (log z) (log 2))))))
(/ (log (gcd z n)) (log 2))))
(define (cdr z)
; n is a power of 3, which is greater than z
(let ((n (expt 3 (ceiling (/ (log z) (log 2))))))
(/ (log (gcd z n)) (log 3))))
My code works well with relatively small test cases:
(define x 12)
(define y 13)
(define z (cons x y))
(car z)
;Value: 12.
(cdr z)
;Value: 12.999999999999998
However, it produces incorrect results when the number grows bigger:
(define x 12)
(define y 14)
(define z (cons x y))
(car z)
;Value: 12.
(cdr z)
;Value: 2.8927892607143724 <-- Expected 14
I want to know what's wrong with my implementation. Is there anything wrong with the algorithm? The idea is that the greatest common devisor of z = 2 ^ x * 3 ^ y and n (a power of 2 which is greater than z) is exactly 2 ^ x.
If my algorithm is correct, is this inconsistency caused by a rounding error and/or an overflow?
One solution is to avoid floating point numbers.
Consider max-power-dividing which finds the maximal exponent k such that p^k divides n:
(define (max-power-dividing p n)
(if (zero? (remainder n p))
(+ 1 (max-power-dividing p (/ n p)))
0))
Then we can write:
(define (car z) (max-power-dividing 2 z))
(define (cdr z) (max-power-dividing 3 z))
As far as I can tell, your solution uses the right idea, but the floating point computation breaks for large numbers.

Racket Function with Two Arguments

I'm trying to review my final exam in R5RS, but having trouble with a simple problem. My professor isn't really helpful and I don't know anybody in my class. Can you help me?
The function ratio takes in two parameters f (function) and x (a number). I had to use a let statement. The scheme function is supposed to produced an outcome for:
f(x)+f(x+1)/f(x)
This is what I have so far:
(define (ratio f x)
(let ((f (+ x 1)))
(/ (+ x (+ f 1))
x)))
(ratio (lambda (x) (+ x 2)) 3)
I tried working with this for an hour, but still can't get the right answer.
Hint: let a = f(x) and let b = f(x + 1). What should the output be in terms of a and b?
In your solution, you bind f to the value of x + 1. So your solution is really calculating (x + (x + 2)) / x. You need to apply f to x, ie (f x).
Here is a start:
(define (ratio f x)
(let ((a (f x)) (b (f (+ x 1))))
...))
Math Scheme
f(x) (f x)
x+1 (+ x 1)
f(x+1) (f (+ x 1))
a/b (/ a b)
a/f(x) (/ a (f x))
f(x+1)/f(x) (/ (f (+ x 1)) (f x))
c + f(x+1)/f(x) ?
f(x) + f(x+1)/f(x) ?

How do I make the substitution ? Scheme

How do I make the substitution? I tried to trace but I don't really get what is going on...
the code:
(define (repeated f n)
(if (zero? n)
identity
(lambda (x) ((repeated f (- n 1)) (f x)))))
f is a function and n is an integer that gives the number of times we should apply f.
....can someone help me to interpret it. I know it returns several procedures and i want to believe that it goes f(f(f(x)))
okey i will re-ask this question but in different manner, because i didn't really get an answer last time. consider this code
(define (repeated f n)
(if (zero? n)
identity
(lambda (x) ((repeated f (- n 1)) (f x)))))
where n is a positive integer and f is an arbitrary function: how does scheme operate on this code lets say we give (repeated f 2). what will happen? this is what think:
(f 2)
(lambda (x) ((repeated f (- 2 1)) (f x))))
(f 1)
(lambda (x) ((lambda (x) ((repeated f (- 1 1)) (f x)))) (f x))))
(f 0)
(lambda (x) ((lambda (x) (identity (f x)))) (f x))))
> (lambda (x) ((lambda (x) (identity (f x)))) (f x))))
> (lambda (x) ((lambda (x) ((f x)))) (f x))))
here is were i get stuck first i want it to go (f(f(x)) but now i will get (lambda x ((f x) (f x)) , the parentheses is certaintly wrong , but i think you understand what i mean. What is wrong with my arguments on how the interpreter works
Your implementation actually delays the further recursion and return a procedure whose body will create copies of itself to fulfill the task at runtime.
Eg. (repeated double 4) ==> (lambda (x) ((repeated double (- 4 1)) (double x)))
So when calling it ((repeated double 4) 2) it runs ((repeated double (- 4 1)) (double 2)))
where the operand part evaluates to (lambda (x) ((repeated double (- 3 1)) (double x))) and so on making the closures at run time so the evaluation becomes equal to this, but in stages during runtime..
((lambda (x) ((lambda (x) ((lambda (x) ((lambda (x) ((lambda (x) (identity x)) (double x))) (double x))) (double x))) (double x))) 2)
A different way of writing the same functionality would be like this:
(define (repeat fun n)
(lambda (x)
(let repeat-loop ((n n)
(x x))
(if (<= n 0)
x
(repeat-loop (- n 1) (fun x))))))
(define (double x) (+ x x))
((repeat double 4) 2) ; ==> 32
You've got a function that takes a function f and an non-negative integer n and returns the function fn, i.e., f(f(f(…f(n)…). Depending on how you think of your recursion, this could be implemented straightforwardly in either of two ways. In both cases, if n is 0, then you just need a function that returns its argument, and that function is the identity function. (This is sort of by convention, in the same way that x0 = 1. It does make sense when it's considered in more depth, but that's probably out of scope for this question.)
How you handle the recursive case is where you have some options. The first option is to think of fn(x) as f(fn-1(x)), where you call f with the result of calling fn-1 with x:
(define (repeated f n)
(if (zero? n)
identity
(lambda (x)
(f ((repeated f (- n 1)) x)))))
The other option is to think of fn(x) as fn-1(f(x)) where _fn-1 gets called with the result of f(x).
(define (repeated f n)
(if (zero? n)
identity
(lambda (x)
((repeated f (- n 1)) (f x)))))
In either case, the important thing to note here is that in Scheme, a form like
(function-form arg-form-1 arg-form-2 ...)
is evaluated by evaluating function-form to produce a value function-value (which should be a function) and evaluating each arg-form-i to produce values arg-value-i, and then calling _function-value_ with the arg-values. Since (repeated ...) produces a function, it's suitable as a function-form:
(f ((repeated f (- n 1)) x))
; |--- f^{n-1} ------|
; |---- f^{n-1}(x) ------|
;|------f(f^{n-1}(x)) ------|
((repeated f (- n 1)) (f x))
; |--- f^{n-1} ------|
;|---- f^{n-1}(f(x))--------|
Based on Will Ness's comment, it's worth pointing out that while these are somewhat natural ways to decompose this problem (i.e., based on the equalities fn(x) = fn-1(f(x)) = f(fn-1(x))), it's not necessarily the most efficient. These solutions both require computing some intermediate function objects to represent fn-1 that require a fair amount of storage, and then some computation on top of that. Computing fn(x) directly is pretty straightforward and efficient with, e.g., repeat:
(define (repeat f n x)
(let rep ((n n) (x x))
(if (<= n 0)
x
(rep (- n 1) (f x)))))
A more efficient version of repeated, then, simply curries the x argument of repeat:
(define (repeated f n)
(lambda (x)
(repeat f n x)))
This should have better run time performance than either of the other implementations.
Danny. I think that if we work repeated with small values of n (0, 1 and 2) will be able to see how the function translates to f(f(f(...(x))). I assume that identity's implementation is (define (identity x) x) (i.e. returns its only parameter as is), and that the "then" part of the if should be (identity f).
(repeated f 0) ;should apply f only once, no repetition
-> (identity f)
-> f
(repeated f 1) ;expected result is f(f(x))
-> (lambda (x) ((repeated f 0) (f x)))
-> (lambda (x) (f (f x))) ;we already know that (repeated f 0) is f
(repeated f 2) ;expected result is f(f(f(x)))
-> (lambda (x) ((repeated f 1) (f x)))
-> (lambda (x) (f (f (f x)))) ; we already know that (repeated f 1) if f(f(x))
... and so on.
Equational reasoning would be very helpful here. Imagine lambda calculus-based language with Haskell-like syntax, practically a combinatory calculus.
Here, parentheses are used just for grouping of expressions (not for function calls, which have no syntax at all – just juxtaposition): f a b c is the same as ((f a) b) c, the same as Scheme's (((f a) b) c). Definitions like f a b = ... are equivalent to (define f (lambda (a) (lambda (b) ...))) (and shortcut for (lambda (a) ...) is (\a-> ...).
Scheme's syntax just obscures the picture here. I don't mean parentheses, but being forced to explicit lambdas instead of just equations and freely shifting the arguments around:
f a b = \c -> .... === f a b c = .... ; `\ ->` is for 'lambda'
Your code is then nearly equivalent to
repeated f n x ; (define (repeated f n)
| n <= 0 = x ; (if (zero? n) identity
| otherwise = repeated f (n-1) (f x) ; (lambda (x)
; ((repeated f (- n 1)) (f x)))))
(read | as "when"). So
repeated f 2 x = ; ((repeated f 2) x) = ((\x-> ((repeated f 1) (f x))) x)
= repeated f 1 (f x) ; = ((repeated f 1) (f x))
= repeated f 0 (f (f x)) ; = ((\y->((repeated f 0) (f y))) (f x))
= f (f x) ; = ((\z-> z) (f (f x)))
; = (f (f x))
The above reduction sequence leaves out the particulars of environment frames creation and chaining in Scheme, but it all works out pretty much intuitively. f is the same f, n-1 where n=2 is 1 no matter when we perform the subtraction, etc..

Resources