lisp Elementary recursion function. Help me trace it - common-lisp

Lisp sigma function recursion - help me trace it. I get it logically, I just need to understand this example so I can do my assignments. I'm not sure what is happening on the 4th and 5th line, what is x being set to. If my inputs are (sigma f 1 2) my output is 20, another example would be (sigma f 1 5). If you can help me trace it. I would post the sigma definition below. Thank you for your help.
(defun sigma (f m n)
(if (> m n)
0
(let ((x (sigma f (+ m 1) n)))
(+ (funcall f m)
x))))

You could also trace your function. Since you need an auxiliary function, let's define myfun, which multiplies its argument by 2.
CL-USER> (defun myfun (x) (* x 2))
MYFUN
TRACE both functions:
CL-USER> (trace sigma myfun)
And then, you should have something like this:
CL-USER> (sigma 'myfun 0 5)
0: (SIGMA MYFUN 0 5)
1: (SIGMA MYFUN 1 5)
2: (SIGMA MYFUN 2 5)
3: (SIGMA MYFUN 3 5)
4: (SIGMA MYFUN 4 5)
5: (SIGMA MYFUN 5 5)
6: (SIGMA MYFUN 6 5)
6: SIGMA returned 0
6: (MYFUN 5)
6: MYFUN returned 10
5: SIGMA returned 10
5: (MYFUN 4)
5: MYFUN returned 8
4: SIGMA returned 18
4: (MYFUN 3)
4: MYFUN returned 6
3: SIGMA returned 24
3: (MYFUN 2)
3: MYFUN returned 4
2: SIGMA returned 28
2: (MYFUN 1)
2: MYFUN returned 2
1: SIGMA returned 30
1: (MYFUN 0)
1: MYFUN returned 0
0: SIGMA returned 30
30

A first thing that might help in understanding this is using more descriptive names:
(defun sigma (some-function current-index end-index) ...)
This function is a pretty typical recursion pattern. First, there is a base case:
(if (> m n) 0 ...)
Once we've reached the end of the loop, we're done. For any f, (sigma f 2 1) is "past the end of the loop" and will always produce 0.
Otherwise, we're not past the end of the loop, so there's a fragment of "call this function again, with the next index":
(sigma f (+ m 1) n)
a fragment of "produce some result for this index":
(funcall f m)
and then a combination of the two:
(let ((x (recursive-sigma-call)))
(+ (value-at-this-index) x))
You might try walking through
(sigma (lambda (x) (* x 2)) 1 2)
expanding each of the forms by hand to see how this works.

Related

Recursive Multiplication in Scheme (positive numbers)

I am new to scheme and am trying to gain an understanding of how the following piece of code is able to recursively multiply two numbers provided (how is the function stack occurring here):
;Recursive Arithmetic
(define increment
(lambda (x)
(+ x 1)))
(define decrement
(lambda (x)
(- x 1)))
(define recursive-add
(lambda (x y)
(if (zero? y)
x
(recursive-add (increment x) (decrement y)))))
"Define Multiplication Recursively"
(define recursive-mult
(lambda (x y)
(if (zero? y)
0
(recursive-add x (recursive-mult x (decrement y)))))) ;else
(recursive-mult 9 5)
My first doubt is what part of the else section is executed first?
In the else section, if (decrement y) is executed first, then y is first decremented by 1, then the(recursive-mult x section runs next by which function calls itself, so the section (recursive-add x never gets called in this same line of code.
Now, if in the else section, the recursive-add x is executed first, x gets added first, then the recursive-mult x runs which runs the the whole function again and the (decrement y) is never reached.
Now I know either of my two assumptions above, or maybe both are wrong. Would someone be able to point me in the right direction please? I apologize if my question displays a high level of inadequacy in this subject but I really want to learn scheme properly. Thank you.
This is an answer in Common Lisp, in which I am more familiar, but the approach is the same. Here is a translation of your code:
(defpackage :so (:use :cl))
(in-package :so)
(defun add (x y)
(if (zerop y)
x
(add (1+ x) (1- y))))
(defun mul (x y)
(if (zerop y)
0
(add x (mul x (1- y)))))
The increment and decrement functions are not defined, I'm using 1+ and 1- which are equivalent.
In the else section, if (decrement y) is executed first, then y is first decremented by 1, then the(recursive-mult x section runs next by which function calls itself, so the section (recursive-add x never gets called in this same line of code.
You can use the substitution model to evaluate recursive functions.
(add (add 1 3) 1)
Let's evaluate first the first argument of the top-most and:
(add (add 2 2) 1)
(add (add 3 1) 1)
(add (add 4 0) 1)
(add 4 1)
Here the call eventually returned and the first argument is 4. Once the execution is resumed, the rest of the code for (add (add 1 3) 1) is executed, which is equivalent to:
(add 5 0)
And finally:
5
Each time you invoke the function a new frame is pushed on the call stack, which is what is shown in a trace:
(trace mul add)
The macro above in Common Lisp makes it so the mul and add functions are traced.
Now when I run a program, a trace is printed when they are entered and exited.
Let's try with small values:
(mul 2 3)
The trace is printed as follows (don't mind the SO:: prefix, this is part of the fully-qualified name of symbols):
0: (SO::MUL 2 3)
1: (SO::MUL 2 2)
2: (SO::MUL 2 1)
3: (SO::MUL 2 0)
3: MUL returned 0
3: (SO::ADD 2 0)
3: ADD returned 2
2: MUL returned 2
2: (SO::ADD 2 2)
3: (SO::ADD 3 1)
4: (SO::ADD 4 0)
4: ADD returned 4
3: ADD returned 4
2: ADD returned 4
1: MUL returned 4
1: (SO::ADD 2 4)
2: (SO::ADD 3 3)
3: (SO::ADD 4 2)
4: (SO::ADD 5 1)
5: (SO::ADD 6 0)
5: ADD returned 6
4: ADD returned 6
3: ADD returned 6
2: ADD returned 6
1: ADD returned 6
0: MUL returned 6
The difference with Scheme is that Scheme does not define the order by which function arguments are evaluated (it is left unspecified), so maybe your code would not exactly behave as above, but it should still compute the same answer (because there are no side effects).
Scheme has eager evaluation so if you have
(op1 expr1 (op2 1 (op3 expr2 expr3)))
Then op1 form will depend on expr1 and the form with op2 to be complete before op1 can be applied. If we have an implementation that
does left to right evaluation it will do it like this:
(let ((vexpr1 expr1)
(vexpr2 expr2)
(vexpr3 expr3))
(let ((vop3 (op3 vexpr2 vexpr3)))
(let ((vop2 (op2 1 vop3)))
(op1 vexpr1 vop2))))
So to answer your question the order in the same left to right Scheme will be:
(let ((vdy (decrement y)))
(let ((vrm (recursive-mult x vdy)))
(recursive-add x vrm)))
Same in CPS:
(decrement& y
(lambda (vdy)
(recursive-mult& x
vy
(lambda (vrm)
(recursive-add& x vrm continuation)))))
So in practice the application for the first round doesn't happen before the whole recursive-mult for the smaller expression happens first. Thus (recursive-mult 3 3) turns into
(recursive-add 3 (recursive-add 3 (recursive-add 3 0)))
And as you can see the last one is being done first, then the second one and the last addition to be performed is the one of the first round before recursion.

Is there a tco pattern with two accumulating variables?

Just for fun (Project Euler #65) I want to implement the formula
n_k = a_k*n_k-1 + n_k-2
in an efficient way. a_k is either 1 or (* 2 (/ k 3)), depending on k.
I started with a recursive solution:
(defun numerator-of-convergence-for-e-rec (k)
"Returns the Nth numerator of convergence for Euler's number e."
(cond ((or (minusp k)) (zerop k) 0)
((= 1 k) 2)
((= 2 k) 3)
((zerop (mod k 3)) (+ (* 2 (/ k 3) (numerator-of-convergence-for-e-rec (1- k)))
(numerator-of-convergence-for-e-rec (- k 2))))
(t (+ (numerator-of-convergence-for-e-rec (1- k))
(numerator-of-convergence-for-e-rec (- k 2))))))
which works for small k but gets pretty slow for k = 100, obviously.
I have no real idea how to transform this function to a version with could be tail-call optimized. I have seen a pattern using two accumulating variables for fibonacci numbers but fail to transform this pattern to my function.
Is there a general guideline how to transform complex recursions to tco versions or should I implement an iterative solution directly.?
First, note that memoization is probably the simplest way optimize your code: it does not reverse the flow of operations; you call your function with a given k and it goes back to zero to compute the previous values, but with a cache. If however you want to turn your function from recursive to iterative with TCO, you'll have to compute things from zero up to k and pretend you have a constant-sized stack / memory.
Step function
First, write a function which computes current n given k, n-1 and n-2:
(defun n (k n1 n2)
(if (plusp k)
(case k
(1 2)
(2 3)
(t (multiple-value-bind (quotient remainder) (floor k 3)
(if (zerop remainder)
(+ (* 2 quotient n1) n2)
(+ n1 n2)))))
0))
This step should be easy; here, I rewrote your function a little bit but I actually only extracted the part that computes n given the previous n and k.
Modified function with recursive (iterative) calls
Now, you need to call n from k starting from 0 to the maximal value you want to be computed, named m hereafter. Thus, I am going to add a parameter m, which controls when the recursive call stops, and call n recursively with the modified arguments. You can see the arguments are shifted, current n1 is the next n2, etc.
(defun f (m k n1 n2)
(if (< m k)
n1
(if (plusp k)
(case k
(1 (f m (1+ k) 2 n1))
(2 (f m (1+ k) 3 n1))
(t (multiple-value-bind (quotient remainder) (floor k 3)
(if (zerop remainder)
(f m (1+ k) (+ (* 2 quotient n1) n2) n1)
(f m (1+ k) (+ n1 n2) n1)))))
(f m (1+ k) 0 n1))))
That's all, except that you don't want to show this interface to your user. The actual function g properly bootstraps the initial call to f:
(defun g (m)
(f m 0 0 0))
The trace for this function exhibits an arrow ">" shape, which is the case with tail-recursive functions (tracing is likely to inhibit tail-call optimization):
0: (G 5)
1: (F 5 0 0 0)
2: (F 5 1 0 0)
3: (F 5 2 2 0)
4: (F 5 3 3 2)
5: (F 5 4 8 3)
6: (F 5 5 11 8)
7: (F 5 6 19 11)
7: F returned 19
6: F returned 19
5: F returned 19
4: F returned 19
3: F returned 19
2: F returned 19
1: F returned 19
0: G returned 19
19
Driver function with a loop
The part that can be slightly difficult, or make your code hard to read, is when we inject tail-recursive calls inside the original function n. I think it is better to use a loop instead, because:
unlike with the tail-recursive call, you can guarantee that the code will behave as you wish, without worrying whether your implementation will actually optimize tail-calls or not.
the code for the step function n is simpler and only expresses what is happening, instead of detailing how (tail-recursive calls are just an implementation detail here).
With the above function n, you can change g to:
(defun g (m)
(loop
for k from 0 to m
for n2 = 0 then n1
for n1 = 0 then n
for n = (n k n1 n2)
finally (return n)))
Is there a general guideline how to transform complex recursions to
tco versions or should I implement an iterative solution directly?
Find a step function which advances the computation from the base case to the general case, and put intermediate variables as parameters, in particular results from past calls. This function can call itself (in which case it will be tail-recursive, because you have to compute all the arguments first), or simply called in a loop. You have to be careful when computing the initial values, you might have more corner cases than with a simple recursive function.
 See also
Scheme's named let, the RECUR macro in Common Lisp and the recur special form in Clojure.

Recursive function returns sum, struggling to understand why?

The following function was given to me on a review sheet:
(define mystery(lambda(m n)
(cond
((= m 0) n)
((= n 0) m)
(#t (+ 2(mystery(- m 1)(- n 1))))
)))
The first two conditions are simple, it's just the recursive otherwise that's confusing me. It just seems to me that the recursion will continue until they both equal zero, which certainly doesn't return the sum. Can someone provide an explanation?
First, let's format the code a bit better to see what's happening:
(define (mystery m n)
(cond ((= m 0) n)
((= n 0) m)
(else (+ 2 (mystery (- m 1) (- n 1))))))
Now, remember that a cond executes only the action corresponding to the first condition that is true (from top to bottom), the others are ignored. If none of the conditions is true, then the else part is executed. The important thing to remember is that only one action is executed.
In particular, your mystery procedure will stop when either m or n becomes zero, not when both become zero. When one of the two reaches zero, the recursion starts to unwind, returning the sum. You can see this when tracing the execution - for example, in Racket:
(require racket/trace)
(trace mystery)
(mystery 3 2)
>(mystery 3 2)
> (mystery 2 1)
> >(mystery 1 0)
< <1
< 3
<5
Just to elaborate on Óscar López's answer (I can't format this in a comment): I find that it's often useful to write these sorts of little recursive maths functions down as if they were maths:
Let m and n be natural numbers, then
n + m = n if m = 0;
n + m = m if n = 0;
n + m = n - 1 + m - 1 + 2;
there are no other cases.
I feel the best way is not to nest but to precompute. Looking at the base case we test with either zero:
(mystery 0 2) ; ==> 2
(nystery 3 0) ; ==> 3
Thus every time at least one argument is zero it returns the other argument. Lets try with a non zero value and remember the second you see a value we have already done before you just switch it with its result:
(mystery 1 3) ; ==
(+ 2 (mystery 0 2)) ; == (we switch known value)
(+ 2 2)
; ==> 4
(mystery 4 1) ; == (we substitute with the expression)
(+ 2 (mystery 3 0)) ; == (we switch known value)
(+ 2 3)
; ==> 5
Since we know the base case always returns the other value we don't need to precalculate it. Here is a go that does that:
(mystery 3 9) ; == (we substitute with the expression)
(+ 2 (mystery 2 8) ; == (we substitute with the expression)
(+ 2 (+ 2 (mystery 1 7))) ; == (we substitute with the expression)
(+ 2 (+ 2 (+ 2 (mystery 0 6))) ; == (we substitute with the expression, n, which is 6)
(+ 2 (+ 2 (+ 2 6))) ; == (we substitute (+ 2 6))
(+ 2 (+ 2 8)) ; == (we substitute (+ 2 8))
(+ 2 10) ; == (we substitute (+ 2 10)
; ==> 12
We can generalize what will happen. The lowest of n and m will decide when the recursion ends. At each step it will add 2 and recurse. Thus it is a fancy way of making:
(define (double-min n m)
(let ((vmin (min n m))
(vmax (max n m)))
(+ (* 2 vmin) (- vmax vmin))))
Which again is a fancy way of adding the two numbers since if n > m, then 2*m+(n-m) = m+m+(n-m) = m+n
(define mystery(lambda(m n)
(cond
((= m 0) n)
((= n 0) m)
(#t (+ 2 (mystery (- m 1) (- n 1))))
)))
First and second conditions are obvious.
Explanation of how the third statement is working:
1 each is taken out of m and n and kept as 2 outside this function.
This is continued till either m is 0 or n is 0.
The first 2 cases are obvious, the sum of 2 numbers where one of the numbers is 0, is equal to the other number.
In the last case, after checking the arguments for 0, we know for sure that both of them are non-0. Assuming that mystery returns the sum of its 2 arguments, then
(+ 2 (mystery (- arg1 1) (- arg2 1)))
will return a sum that is equal to (mystery arg1 arg2) and will eventually halt when one of the arguments is 0, returning the desired result.
Assuming that mystery returns the sum of its 2 arguments is key here and is called the recursive leap of faith. (Google it)

How to solve negative Power in Lisp

Today, we used LISP for the first time in our Artificial Intelligence class. Well, the LISP compiler was not readily available, so we dry run every code.
I am currently having a problem with the POWER function when it is raised to a negative number. I asked the lecturer and he said I should do that myself and boasted he will set it in the exam coming up on Wednesday. I searched online, I found some tutorials saying it will produce an error and you should output a customized error message, just then I remembered Stackoverflow.
Here is a sample program I did already but the power is a positive integer.
(DE POWER (M N)
(COND ((ZEROP N) 1)
(T (TIMES M (POWER M (SUB 1 N)))))
Example
M = 4, N = 3
(POWER 4 3)
(TIMES 4 (POWER 4 2))
(TIMES 4 (TIMES 4 (POWER 4 1)))
(TIMES 4(TIMES 4(TIMES 4 ( POWER 4 0))))
(TIMES 4(TIMES 4 (TIMES 4 1)))
(TIMES 4 (TIMES 4 4))
(TIMES 4 16)
64
Now, how can solve the following using a LISP program?
M = 4, N = -3
Are there any function to tackle negative powers in LISP or is there a systematic step to solve this?
M^(-N) = 1 / (M^N). So you can check for negative N and return 1 / M^(-N).
(DE POWER (M N)
(COND ((ZEROP N) 1)
((< N 0) (/ 1 (POWER M (- 0 N))))
(T (TIMES M (POWER M (SUB 1 N)))))

Recursive Addition in Lisp

I'm a beginner and I am trying to teach myself Common Lisp and during my self-study I have written a function that I believe should work for recursive addition of two arguments. However, the function always fails. Why is that?
(defun sum (n m)
;;;Returns the sum of n and m using recursion
(cond ((eq m 0) n))
(sum (1+ n) (1- m)))
As I understand it, it should continually add 1 to n while decrementing m until m is 0 at which point, the recursive addition is complete
I think you have 2 simple typos:
one parenthesis too many and
missing t in your cond clause.
What you probably meant was:
(defun sum (n m)
(cond
((eq m 0) n) ; here you had one parenthesis too many
(t (sum (1+ n) (1- m))))) ; here you were missing the `t` symbol
It's really wierd use case to do such addition, but I'll explain you where is your mistakes:
(defun sum (n m)
;;;Returns the sum of n and m using recursion
(cond ((eq m 0) n)) ;; <= This line is ignored, you not returnin N.
(sum (1+ n) (1- m))) ;; <= this will be called forever
You should write:
(defun sum (n m)
"Recursively increment N and decrement M untill M = 0"
(if (= m 0) ;; don't use EQ for numbers, use EQL or =.
n
(sum (1+ n) (1- m)))) ;; Otherwise recursive call
Let's trace it to see how it works:
CL-USER> (sum 0 10)
0: (SUM 0 10)
1: (SUM 1 9)
2: (SUM 2 8)
3: (SUM 3 7)
4: (SUM 4 6)
5: (SUM 5 5)
6: (SUM 6 4)
7: (SUM 7 3)
8: (SUM 8 2)
9: (SUM 9 1)
10: (SUM 10 0)
10: SUM returned 10
9: SUM returned 10
8: SUM returned 10
7: SUM returned 10
6: SUM returned 10
5: SUM returned 10
4: SUM returned 10
3: SUM returned 10
2: SUM returned 10
1: SUM returned 10
0: SUM returned 10
10
If you'll take an advice - don't try to do such weird things with recursion, if you want to leard how to use it, try it for some natural-recursive cases like factorials, fibonacci, tree processing and such.

Resources