Factoring out a procedure - scheme

How could I use this procedure:
(define (sum f n )
(if (= n 1)
(f 1)
(+ ( f n ) (sum f (- n 1)))))
in order to redefine the following one?
(define (zeno n)
(cond ((= n 1)
(/ 1 2))
((> n 1)
(+ (zeno (- n 1))
(/ 1 (expt 2 n))))))
Basically, I am trying to create another function called zeno-sec that uses the sum function written above.

The procedure sum accepts another procedure f and you have to find that f. If you look at the second procedure zeno you can spot a possible body of f in the second clause of cond, that is (/ 1 (expt 2 n)). So f will be (lambda (a) (/ 1 (expt 2 a))). Combining it with sum, the zeno-sec will look like:
(define (zeno-sec n)
(sum (lambda (a)
(/ 1 (expt 2 a)))
n))
Edit: Maybe some clarifications could help. If you look at the two procedures, sum and zeno, you can see they have very similar structure: a conditional form and a recursion. Also if you switch the places of the subexpressions in the last expressions you will notice that they are almost the same:
(+ (sum f (- n 1))
(f n))
and
(+ (zeno (- n 1))
(/ 1 (expt 2 n)))
See how the call (zeno (- n 1)) resembles the (sum f (- n 1)) and the (f n) becomes (/ 1 (expt 2 n)). I hope that makes some sense.

Related

MIT-Scheme SICP Exercise_1.11 -- object #t is not applicable

This is my first post on StackOverflow. I have been working on Exercise 1.11 from SICP and feel I have a viable solution. In transferring from paper to Emacs I seem to have some syntax error that I am unaware of. I tried my best to double and triple check the parenthesis and solve it but the terminal is still giving me an 'object #t is not applicable' message. Could someone please point me in the right direction of how to fix the code so I can test its output properly?"
Exercise 1.11: A function f
is defined by the rule that:
f(n)=n
if n<3
, and
f(n)=f(n−1)+2f(n−2)+3f(n−3)
if n>=3
Write a procedure that computes f by means of a recursive process.
Write a procedure that computes f by means of an iterative process.
(define (f-recur n)
(if ((< n 3) n)
(+ (f(- n 1))
(* 2 (f(n-2)))
(* 3 (f(n-3)))))
(define (f-iter n)
(define (counter n)
(if (<= n 3) 0)
(- n 3))
(define (d n) (+ n (* 2 n) (* 3 n)))
(define (c n) (+ d (* 2 n) (* 3 n)))
(define (b n) (+ c (* 2 d) (* 3 n)))
(define (a n) (+ b (* 2 c) (* 3 d)))
(define (f a b c d counter)
(if ((> (+ counter 3) n) a)
(f (+ b (* 2 c) (* 3 d)) a b c (+ counter 1)))))
(cond ((= counter 0) d)
((= counter 1) c)
((= counter 2) b)
((= counter 3) a)
(else (f a b c d counter))))
I'm pretty sure SICP is looking for a solution in the manner of this iterative fibonnacci:
(define (fib n)
(define (helper n a b)
(if (zero? n)
a
(helper (- n 1) b (+ a b))))
(helper n 0 1))
Fibonacci is f(n)=f(n−1)+f(n−2) so I guess f(n)=f(n−1)+2f(n−2)+3f(n−3) can be made exactly the same way with one extra variable. Your iterative solution looks more like Fortran than Scheme. Try avoiding set!.

Scheme function as parameter

the program is supposed to use
(define (sum f n)
(if (= n 0)
(f 1)
(+ (f n) (sum f (- n 1)))))
(define (harm-term k)
(/ 1 k))
(define (harm-sum n)
(sum (harm-term 1) n))
to create a function called harm-sum that calculates the sum of harmonic series. But I keep getting the error
application:
not a procedure;
expected a procedure that can be applied to arguments
given: 3
arguments...:
for the sum function.
(define (sum f n)
(if (= n 0)
(f 1)
(+ (f n) (sum f (- n 1)))))
(define (harm-term k)
(/ 1 k))
(define (harm-sum n)
(sum (harm-term 1) n))
The way that you are eventually calling sum is wrong because you call sum with (harm-term 1) as the parameter that you are expecting a function for. (harm-term 1) clearly evaluates to a 1.
This means that when it is used later in sum as the parameter f it makes no sense (i.e. you eventually call (1 1))
You should be doing something like this:
(define (sum f n)
(if (= n 0)
(f 1)
(+ (f n) (sum f (- n 1)))))
(define (harm-term k)
(/ 1 k))
(define (harm-sum n)
(sum harm-term n)) ; the difference is the function itself is passed instead of the value the function returns for 1

Scheme - speed up a heavily recursive function

I must write a Scheme predicate that computes the function f(N -> N) defined as :
if n < 4 :f(n)= (n^2) + 5
if n ≥ 4 :f(n) = [f(n−1) + f(n−2)] * f(n−4)
I wrote a simple predicate that works :
(define functionfNaive
(lambda (n)
(if (< n 4) (+ (* n n) 5)
(* (+ (functionfNaive (- n 1)) (functionfNaive (- n 2)))
(functionfNaive (- n 4))))))
Now, I try a method with an accumulator but it doesn't work...
My code :
(define functionf
(lambda(n)
(functionfAux n 5 9 14)))
(define functionfAux
(lambda (n n1 n2 n4)
(cond
[(< n 4) (+ (* n n) 5)]
[(= n 4) (* n1 (+ n2 n4))]
[else (functionfAux (- n 1) n2 n4 (* n1 (+ n2 n4)))])))
As requested, here's a memoized version of your code that performs better than the naïve version:
(define functionf
(let ((cache (make-hash)))
(lambda (n)
(hash-ref!
cache
n
(thunk
(if (< n 4)
(+ (* n n) 5)
(* (+ (functionf (- n 1)) (functionf (- n 2))) (functionf (- n 4)))))))))
BTW... computing the result for large values of n is very quick, but printing takes a lot of time. To measure the time, use something like
(time (functionf 50) 'done)
AND here's a generic memoize procedure, should you need it:
(define (memoize fn)
(let ((cache (make-hash)))
(λ arg (hash-ref! cache arg (thunk (apply fn arg))))))
which in your case could be used like
(define functionf
(memoize
(lambda (n)
(if (< n 4)
(+ (* n n) 5)
(* (+ (functionf (- n 1)) (functionf (- n 2))) (functionf (- n 4)))))))
First, that's not a predicate. A Predicate is a function which returns a Boolean value.
To calculate the nth result, start with the first four and count up, maintaining the last four known elements. Stop when n is reached:
(define (step a b c d n)
(list b c d (* (+ c d) a)) (+ n 1)))
etc. Simple. The first call will be (step 5 6 9 14 3).
The depth of the recursion tree may be the biggest question, so may be use the iteration which means use some variables to memory the intermediate processes.
#lang racket
(define (functionf n)
(define (iter now n1 n2 n3 n4 back)
(if (= n now)
back
(iter (+ now 1) back n1 n2 n3 (* n3 (+ back n1)))))
(if (< n 4)
(+ 5 (* n n))
(iter 4 14 9 6 5 125)))
(functionf 5)
in this way, the depth of the stack only be 1 and the code is speeded up.

Count Fibonacci "cost" in scheme

I have to make a function that finds the "cost" of a Fibonacci number. My Fibonacci code is
(define fib (lambda (n) (cond
((< n 0) 'Error)
((= n 0) 0)
((= n 1) 1)
(else (+ (fib (- n 1)) (fib (- n 2)))))))
Each + or - that is used to evaluate a fib number is worth $1. Each < or > is worth $0.01. For example, 1 is worth $0.01, 2 is worth $3.03, etc. I don't know how to count the number of +, -, <, and >. Do I need the fib code in my fibCost code?
I'm not sure whether or not you wanted the solution to include the original code or not. There are direct ways of computing the cost, but I think it's interesting to look at ways that are similar to instrumenting the existing code. That is, what can we change so that something very much like the original code will compute what we want?
First, we can replace the arithmetic operators with a bit of indirection. That is, instead of calling (+ x y), you can call (op + 100 x y), which increments the total-cost variable.
(define (fib n)
(let* ((total-cost 0)
(op (lambda (fn cost . args)
(set! total-cost (+ total-cost cost))
(apply fn args))))
(let fib ((n n))
(cond
((op < 1 n 0) 'error)
((= n 0) 1)
((= n 1) 1)
(else (op + 100
(fib (op - 100 n 1))
(fib (op - 100 n 2))))))
total-cost))
That doesn't let us keep the original code, though. We can do better by defining local versions of the arithmetic operators, and then using the original code:
(define (fib n)
(let* ((total-cost 0)
(op (lambda (fn cost)
(lambda args
(set! total-cost (+ total-cost cost))
(apply fn args))))
(< (op < 1))
(+ (op + 100))
(- (op - 100)))
(let fib ((n n))
(cond
((< n 0) 'error)
((= n 0) 1)
((= n 1) 1)
(else (+ (fib (- n 1))
(fib (- n 2))))))
total-cost))
> (fib 1)
1
> (fib 2)
303
> (fib 3)
605
> (fib 4)
1209
What's nice about this approach is that if you start using macros to do some source code manipulation, you could actually use this as a sort of poor-man's profiler, or tracing system. (I'd suggest sticking with the more robust tools provided by the implementation, of course, but there are times when a technique like this can be useful.)
Additionally, this doesn't even have to compute the Fibonnaci number anymore. It's still computed because we do (apply fn args), but if we remove that, then we never even call the original arithmetic operation.
The quick and dirty solution would be to define a counter variable each time the cost procedure is started, and update it with the corresponding value at each branch of the recursion. For example:
(define (fib-cost n)
(let ((counter 0)) ; counter initialized with 0 at the beginning
(let fib ((n n)) ; inner fibonacci procedure
; update counter with the corresponding cost
(set! counter (+ counter 0.01))
(when (> n 1)
(set! counter (+ counter 3)))
(cond ((< n 0) 'Error)
((= n 0) 0)
((= n 1) 1)
(else (+ (fib (- n 1)) (fib (- n 2))))))
counter)) ; return the counter at the end
Answering your second question - no, we don't need the whole fib code; given that we're not interested in the actual value of fibonacci, the above can be further simplified to just make the required calls and ignore the returned values:
(define (fib-cost n)
(let ((counter 0)) ; counter initialized with 0 at the beginning
(let fib ((n n)) ; inner fibonacci procedure
; update counter with the corresponding cost
(set! counter (+ counter 0.01))
(when (> n 1)
(fib (- n 1))
(fib (- n 2))
(set! counter (+ counter 3))))
counter)) ; return the counter at the end
You have +/- just anytime you call the code recursively, in the else Part. So, easily anytime you enter the else part, you should count 3 of them. One for f(n-1), one for f(n-2) and one for f(n-1) + f(n-2).
Just for fun, a solution using syntactic extensions (aka "macros").
Let's define the following:
(define-syntax-rule (define-cost newf oldf thiscost totalcost)
(define (newf . parms)
(set! totalcost (+ totalcost thiscost))
(apply oldf parms)))
Now we create procedures based on the original procedures you want to have a cost:
(define-cost +$ + 100 cost)
(define-cost -$ - 100 cost)
(define-cost <$ < 1 cost)
so using +$ will do an addition and increase a cost counter by 1, and so on.
Now we adapt your inititial procedure to use the newly defined ones:
(define fib
(lambda (n)
(cond
((<$ n 0) 'Error)
((= n 0) 0)
((= n 1) 1)
(else
(+$ (fib (-$ n 1)) (fib (-$ n 2)))))))
For convenience, we create a macro to return both the result of a procedure and its cost:
(define-syntax-rule (howmuch f . args)
(begin
(set! cost 0)
(cons (apply f 'args) cost)))
then a cost variable
(define cost #f)
and off we go
> (howmuch fib 1)
'(1 . 1)
> (howmuch fib 2)
'(1 . 303)
> (howmuch fib 10)
'(55 . 26577)
> (howmuch fib 1)
'(1 . 1)

Collatz function in scheme

So i'm trying to solve the collatz function iteratively in scheme but my test cases keep showing up as
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
1
(if (even? n) (collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1))
)
)
)
)
However, my test cases keep resulting in "#[constant 13 #x2]". What did I write wrong, if anything?
You forgot to call collatz-iter. Also, it's not clear what do you intend to do with counter, you just increment it, but never actually use its value - your procedure will always return 1 (assuming that the Collatz conjecture is true, which seems quite possible).
I'm guessing you intended to return the counter, so here's how to fix your procedure:
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
counter ; return the counter
(if (even? n)
(collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1)))))
(collatz-iter n 1)) ; call collatz-iter
And this is how it works for the examples in wikipedia:
(collatz 6)
=> 9
(collatz 11)
=> 15
(collatz 27)
=> 112
So basically we're counting the length of the Collatz sequence for a given number.
You should indent your code properly. With proper formatting, it's
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
1
(if (even? n)
(collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1))))))
which clearly has no body forms to execute, just an internal definition. You need to add a call to collatz-iter, like this:
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
1
(if (even? n)
(collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1)))))
(collatz-iter n 1))
(I'm not sure what your initial counter value should be. I'm assuming 1 is reasonable, but perhaps it should be zero?) Better yet, since the body it just a call to collatz-iter, you can make this a named let, which is more like your original code:
(define (collatz n)
(let iter ((n n) (counter 1))
(if (<= n 1)
1
(if (even? n)
(iter (/ n 2) (+ counter 1))
(iter (+ (* n 3) 1) (+ counter 1))))))
It's sort of like combining the internal definition with the single call to the local function. Once you've done this, though, you'll see that it always returns 1, when it eventually gets to the base case (assuming the Collatz conjecture is true, of course). Fixing this, you'll end up with:
(define (collatz n)
(let iter ((n n) (counter 1))
(if (<= n 1)
counter
(if (even? n)
(iter (/ n 2) (+ counter 1))
(iter (+ (* n 3) 1) (+ counter 1))))))
When I try to run your code in Racket I get the error:
no expression after a sequence of internal definitions
This is telling us that the collatz function conatains the collatz-iter definition, but no expression to call it (other than the recursive calls in collatz-iter). That can be fixed by adding a call to (collatz-iter n 0) as the last line in collatz.
However, when you run the program it always returns 1. Not very interesting. If instead you change it to return the value of counter you can see how many steps it took for the sequence to reach 1.
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
counter
(if (even? n) (collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1))
)
)
)
(collatz-iter n 0)
)
We can check it against a few examples given on the Wikipedia Collatz conjecture article.
> (collatz 6)
8
> (collatz 11)
14
> (collatz 27)
111
>

Resources