SICP exercise 1.10: Scheme evaluation of Ackermann's function - scheme

I'm working through Structure and Interpretation of Computer Programs and have a question concerning exercise 1.10, which, using Ackermann's function defined as
(define (A x y)
(cond ((= y 0) 0)
((= x 0) (* 2 y))
((= y 1) 2)
(else (A (- x 1)
(A x (- y 1))))))
determine the value of the expression (A 1 10).
Now, I know the answer should be (A 1 10) = 2^10 = 1024, but when working through the computation, I get the following:
(A 1 10)
(A (- 1 1) (A 1 (- 10 1)))
(A 0 (A 1 9))
(A 0 (A 0 (A 1 8)))
...
(A 0 (A 0 (A 0 (A 0 (A 0 (A 0(A 0 (A 0 (A 0(A 0 (A 0 (A 0 ( A 0 0)))))))))))))
Now, the way I understood it, Scheme will start by evaluating the deepest expressions first, i.e. the (A 0 0) on the far right. This has the value 0, as the first condition of the function is met with (= y 0). The same happens for the next step and we end up reducing all brackets until we end up with the last (A 0 0) which will also have the value 0 for analogous reasons. Now, I get that the last line should be something like
(*2 (*2 (*2 (*2 (*2 (*2 (*2 (*2 (*2 (*2 (*2 (A 0 0)))))))))))))
So, if all of this is correct, why does the last (A 0 0) yield 2 instead of 0? Or, more generally, can you spot where the error in my reasoning is? I'm pretty sure it either has something do to with the evaluation procedure of recursive calls OR with how conditional statements are evaluated.
Solved: As noted by leppie the (= y 1) gets evaluated first, getting 2 as value for (A 0 1) before getting to (A 0 0)

You never get all the way to
(A 0 0)
The expansion proceeds
(A 0 (A 1 9))
(A 0 (A 0 (A 1 8)))
(A 0 (A 0 (A 0 (A 1 7))))
...
(A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 1))))))))))
and now the (A 1 1) is evaluated to 2.

Related

Recursive Pascal in Scheme - Unable to find the correct algorithm

(define (pascal x y)
(cond ((or (<= x 0) (<= y 0) (< x y )) 0)
((or (= 1 y) (= x y) ) 1)
(else (+ (pascal (- x 1) y) (pascal (- x 1) (- y 1))))))
This is the function I have for a recursive pascal call that should return the number given the x and y of the triangle.
1
11
121
1331
14641
If I enter pascal 0 0, it should return 1, however it returns 0;
If I enter pascal 4 2, it should return 6, but it returns 3;
Seems like my base is off but I'm not sure how I can change it without ruining the calculation for pascals algorithm. Could someone point me to the right direction
You are very close, but your conditions aren't quite doing what you think they are. You have something like an off-by-1 error, and you haven't properly split apart your cond cases.
#lang racket/base
(for ((x (in-range 1 6)))
(for ((y (in-range (add1 x))))
(printf "~a " (pascal x y)))
(newline))
0 1
0 1 1
0 1 2 1
0 1 3 3 1
0 1 4 6 4 1
I make some small changes to your conditions and get this output:
(for ((x (in-range 6)))
(for ((y (in-range (add1 x))))
(printf "~a " (pascal x y)))
(newline))
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
If this doesn't help I can edit later and put the solution in, but this smells like homework and I don't want to just post a solution.

Set Individual Elements of Multidimensional Vectors in Racket

For a university project i have to make a game based in a matrix in the pretty big language, the matrix is being defined as a multidimensional vector.
I need to set a single element of the matrix, my code is:
(require racket/vector)
(define test (make-vector 4 (make-vector 4 0)))
(define (matrix-set matrix row column value)
(vector-set! (vector-ref matrix row) column value)
)
(display test)(newline)
(matrix-set test 0 0 1)
(display test)
And outputs this:
#(#(0 0 0 0) #(0 0 0 0) #(0 0 0 0) #(0 0 0 0))
#(#(1 0 0 0) #(1 0 0 0) #(1 0 0 0) #(1 0 0 0))
I have searched the racket documentation and only found functions that set an element by making a new matrix, this and this questions too.
Why is the function setting the whole column instead of only the element?
What can be done to resolve it?
(make-vector 4 (make-vector 4 0)) is the same as:
(let ((x (make-vector 4 0)))
(vector x x x x))
That is, (make-vector 4 0) is called only once, and its value is used for all 4 slots of the outer vector.
What you need is something like (for/vector ((i 4)) (make-vector 4 0)), which will call (make-vector 4 0) (and create a distinct vector) for each element of the outer vector.
An alternative approach is to use the vector generating iterator for/vector. I'm not sure the syntax is any cleaner than using thunks, but conceptually, I feel it is more familiar and perhaps simpler.
(define test (for/vector ([i (range 4)])(make-vector 4 0)))
(matrix-set test 0 0 1) ; '#(#(1 0 0 0) #(0 0 0 0) #(0 0 0 0) #(0 0 0 0))
A third alternative, that isn't as Racket like, would be using do.
(define test
(do ((vec (make-vector 4))
(i 0 (+ i 1)))
((= i 4) vec)
(vector-set! vec i (make-vector 4 0))))
On the other hand, sometimes it's worth knowing a bit about do because do don't require memorizing a different command for each type since do does what it does on vectors, lists, and hashes.

Define a Scheme procedure (bitAdder x a b) to simulate the logic design

Define a Scheme procedure (bitAdder x a b) to simulate the logic design given in following the diagram in Figure 2. The procedure must call the gate procedures that you defined in Question 1 and must return a pair with two elements '(s . c), where s is the binary sum of a, b, and x, while c is the carry-out. You will implement the procedure in three steps using three procedures, as listed below.
Write a procedure (sum-bit x a b) to generate the result bit s.
Write a procedure (carry-out x a b) to generate the carry-out bit c.
Write a procedure (bitAdder x a b) to generate the pair out put (s . c).
So far I have defined my logic gates for "and", "or" , and "xor". I tried to do the first two procedures but they seem incorrect.
(define AND-gate (lambda (a b)
(if (= a b 1)
1
0)))
(define OR-gate (lambda (a b)
(if (= a 1)
1
(if (= b 1)
1
0))))
(define XOR-gate (lambda (a b)
(if (= a b)
0
1)))
(define sum-bit (lambda (x a b)
(XOR-gate a b)
(XOR-gate x (XOR-gate a b))))
(define carry-out (lambda (x a b)
(OR-gate a b)
(AND-gate (OR-gate a b) x)
(AND-gate a b)
(OR-gate (AND-gate a b) (AND-gate (OR-gate a b) x))))
Define the Gates
#lang racket
(define (AND-gate A B)
(if (= A B 1)
1
0))
(define (XOR-gate A B)
(if (not (= A B))
1
0))
(define (OR-gate A B)
(if (not (= 0 (+ A B)))
1
0))
Test the Gates
(module+ test
(require rackunit
rackunit/text-ui)
(define-test-suite
gate-tests
(test-equal? "AND-gate" (AND-gate 1 1) 1)
(test-equal? "XOR-gate" (XOR-gate 0 1) 1)
(test-equal? "XOR-gate" (XOR-gate 1 0) 1)
(test-equal? "XOR-gate" (XOR-gate 0 0) 0)
(test-equal? "XOR-gate" (XOR-gate 1 1) 0)
(test-equal? "AND-gate" (AND-gate 0 0) 0)
(test-equal? "AND-gate" (AND-gate 0 1) 0)
(test-equal? "AND-gate" (AND-gate 1 0) 0)
(test-equal? "OR-gate" (OR-gate 0 0) 0)
(test-equal? "OR-gate" (OR-gate 1 0) 1)
(test-equal? "OR-gate" (OR-gate 0 1) 1)
(test-equal? "OR-gate" (OR-gate 1 1) 1))
(run-tests gate-tests))
Define Sum-Bit
(define (sum-bit X A B)
(XOR-gate X (XOR-gate A B)))
Test Sum-Bit
(module+ test
(define-test-suite
sum-bit-tests
(test-equal? "Sum-bit" (sum-bit 0 0 0) 0)
(test-equal? "Sum-bit" (sum-bit 1 0 0) 1)
(test-equal? "Sum-bit" (sum-bit 0 1 0) 1)
(test-equal? "Sum-bit" (sum-bit 0 0 1) 1)
(test-equal? "Sum-bit" (sum-bit 1 1 0) 0)
(test-equal? "Sum-bit" (sum-bit 1 0 1) 0)
(test-equal? "Sum-bit" (sum-bit 0 1 1) 0)
(test-equal? "Sum-bit" (sum-bit 1 1 1) 1))
(run-tests sum-bit-tests))
Define Carry-Bit
(define (carry-bit X A B)
(OR-gate (AND-gate A B)
(OR-gate (AND-gate X A)
(AND-gate X B))))
Test Carry-Bit
(module+ test
(define-test-suite
carry-bit-tests
(test-equal? "Carry-bit" (carry-bit 0 0 0) 0)
(test-equal? "Carry-bit" (carry-bit 1 0 0) 0)
(test-equal? "Carry-bit" (carry-bit 0 1 0) 0)
(test-equal? "Carry-bit" (carry-bit 0 0 1) 0)
(test-equal? "Carry-bit" (carry-bit 1 1 0) 1)
(test-equal? "Carry-bit" (carry-bit 1 0 1) 1)
(test-equal? "Carry-bit" (carry-bit 0 1 1) 1)
(test-equal? "Carry-bit" (carry-bit 1 1 1) 1))
(run-tests carry-bit-tests))
Define Bit-Adder
(define (bit-adder X A B)
(cons (sum-bit X A B)
(carry-bit X A B)))
Test Bit-Adder
(module+ test
(define-test-suite
bit-adder-tests
(test-equal? "Bit-adder" (bit-adder 0 0 0) '(0 . 0))
(test-equal? "Bit-adder" (bit-adder 1 0 0) '(1 . 0))
(test-equal? "Bit-adder" (bit-adder 0 1 0) '(1 . 0))
(test-equal? "Bit-adder" (bit-adder 0 0 1) '(1 . 0))
(test-equal? "Bit-adder" (bit-adder 1 1 0) '(0 . 1))
(test-equal? "Bit-adder" (bit-adder 1 0 1) '(0 . 1))
(test-equal? "Bit-adder" (bit-adder 0 1 1) '(0 . 1))
(test-equal? "Bit-adder" (bit-adder 1 1 1) '(1 . 1)))
(run-tests bit-adder-tests))
Run the Tests
racket#297774346.rkt> ,enter "/home/ben/StackOverflow/297774346.rkt"
12 success(es) 0 failure(s) 0 error(s) 12 test(s) run
0
8 success(es) 0 failure(s) 0 error(s) 8 test(s) run
0
8 success(es) 0 failure(s) 0 error(s) 8 test(s) run
0
8 success(es) 0 failure(s) 0 error(s) 8 test(s) run
0
Turn in Homework
Subject to academic policies regarding the work of others.

Pascal's Triangle with a Twist

Say we want to generate Pascal's Triangle within Scheme, but with a twist. For the function (pascal left right depth), where left is the number on the left side of the triangle and right is the number on the right. For example a call of (pascal 1 1 5) would return
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
and a call to (pascal 1 2 5) would return
1
1 2
1 3 2
1 4 5 2
1 5 9 7 2
1 6 14 16 9 2
How would you print the triangle out so that it is spaced like the examples?
My code so far is as follows but all this does is return which number should be at which location within the standard triangle.
(define (pascal x y)
(cond ((or (<= x 0) (<= y 0) (< x y)) 0)
((or (= 1 y) (= x y)) 1)
(else (+ (pascal (- x 1) y) (pascal (- x 1) (- y 1))))))
Add a decreasing number of spaces to the start of each line. Determine the number from the length of the last line and the length of the current line to be printed.

Scheme - printing to screen - Normal eval

Why in the next code, nothing is displayed when we work on Normal eval (lazy one).
;;; [Number, Number -> Number]
(define (printing-sub x y)
(display x)
(- x y))
;;; [Number, Number -> Number]
(define (f a b)
(if (< a 0)
a
(f b (printing-sub b a))))
(f 0 0)
I'll exmplain: In the first iteration, we will got (f 0 (printing-sub 0 0)), in the 2nd: (f (prining-sub 0 0) (prining sub (printing sub 0 0) 0). Now, in the 3rd, we have to calculate (printing-sub 0 0) because we want to know (if (<a 0). In this iteration 0 will print out.
What am I missing?
Thank you.
I too don't know what you mean by "normal eval", but I don't understand why you would expect anything but 0 to be printed out with that code. In fact it'll cause an infinite loop, printing out endless zeroes.
Note that (printing-sub 0 0) will always just display 0 and return 0, because (- 0 0) is 0. So in the first iteration you get (f 0 (printing-sub 0 0)) which reduces back to (f 0 0) which causes the infinite loop.
In other words, the if always evaluates to #f because a will never become anything other than 0.

Resources