Tail call optimization by the compiler/interpreter for factorial function in Scheme [duplicate] - scheme

This question already has an answer here:
Turning structural recursion into accumulative recursion in Racket
(1 answer)
Closed 4 years ago.
Is it possible to perform tail call optimization by the compiler/interpreter for the factorial function given below?
(define factorial
(lambda (x)
(if (= x 0)
1
(* x (factorial (- x 1))))))
I would like to get a brief explanation for the same.
From the comment by #rsm below I understand program should be written something like this:
(define fact
(lambda (x accumulator)
(if (<= x 1)
accumulator
(fact (- x 1) (* x accumulator)))))
(define factorial
(lambda (x)
(fact x 1)))
Or something like this:
(define factorial
(lambda (n)
(let fact ([i n] [a 1])
(if (= i 1)
a
(fact (- i 1) (* a i))))))

First, a terminological issue: you, as the programmer, cannot "do" tail call optimization. (This is one of the reasons why "tail call optimization" is a bad name for this property.) In this case, the "optimization" is done by the evaluator; specifically, a correct evaluator for Racket or Scheme or any properly tail-calling language makes a promise: it promises not to use unbounded memory on certain types of programs. Specifically, programs that make only "tail calls."
So, what you're really asking is how you can convert your program to one that makes only tail calls. The key here is to understand tail calls, and to convert your program to accumulator style. And, at this point, I'm going to defer to the excellent discussion that appears in Alexis King's answer.

It looks like you are trying to calculate x!.
You defined factorial as a lambda with input x (here it is in a readable pseudocode, not a prefix syntax as in Scheme):
factorial (x) = {
(x=0) -> 1 // end condition
(x<>0) -> x * fact(x-1) // 'fact' should be 'factorial' AFAIK
}
or in other words:
factorial(x) * factorial(x-1) * factorial((x-1)-1) ...factorial(0) => x!
the following is already tail recursive ( a recursion were the last call is the recursion):
factorial (x , sum(1)) = {
(x=0) -> sum // end condition
(x<>0) -> fact(x-1 , sum(x*sum)) // 'fact' should be 'factorial' AFAIK
}
back to code, should be something like:
(define factorial
(lambda (x , sum=1)
(if (= x 0)
sum
(fact (- x 1) (* x sum)))))

Related

Multiplication as repeated addition?

I am new to Scheme. I am attempting to write a program that defines (integer) multiplication as repeated addition. In python the program would look something like:
a = int(raw_input(['please enter a number to be multiplied']))
b = int(raw_input(['please enter a number to multiply by']))
y = a
print y
for i in range(b-1):
y+=a
print y
There are two problems I have when attempting to write in Scheme, one 'hard' and one 'soft':
The 'hard' problem: I cannot find an equivalent of the range function in Scheme. How should I implement this?
The 'soft' problem: At this point in the book, for loops have not been introduced for Scheme, which leads me to believe the solution does not contain a for loop; however, I am fine with using a for loop if that is easier/better.
You use recursion in place of iteration. The general idea is:
mult(a, b)
if b == 0, return 0
return a + mult(a, b-1)
Now, can you code that in Scheme on your own?
In Racket (a Scheme derivative) there is "named let" where one can keep adding in each loop for b times (easier to understand this concept):
(let loop ((n 0)
(s 0))
(cond
([= n b] s)
(else (loop (add1 n) (+ s a)))))
DrRacket Scheme code should be like that:
(define mult
(lambda (a b)
(if (= b 0)
b
(+ a (mult a (- b 1))))))
(mult 4 5)

Why doesn't this Racket code terminate?

I'm reading about lazy evaluation and having trouble understanding a basic example they gave.
#lang racket
(define (bad-if x y z)
(if x y z))
(define (factorial-wrong x)
(bad-if (= x 0)
1
(* x (factorial-wrong (- x 1)))))
(factorial-wrong 4)
I'm a little confused as to why this program never terminates. I know the following code works just fine:
(define (factorial x)
(if (= x 0)
1
(* x (factorial (- x 1)))))
(factorial 4)
So I'm assuming it has something to do with scope. I tried step by step debugging and factorial-wrong executes the recursion function even when x is mapped to 0.
The standard if
(if test-expr then-expr else-expr)
will only evaluate either then-expr or else-expr, depending on test-expr, because this if is either a special form or a syntactic extension based on a special form, which means it doesn't follow the normal evaluation rules.
bad-if, on the other hand, is a standard procedure. In that case, Scheme first evaluates both expressions since they are parameters to the procedure bad-if before actually executing bad-if. So, even for x = 0, (* x (factorial -1)) will be evaluated, which will in turn evaluate (* x (factorial -2)) and so on, in an endless loop.
Use the stepper!
To be more specific:
Snip the #lang racket off the top of your program
Change the language level to "Intermediate Student"
Click on the Step button. Watch carefully to see where things go off the rails.

Continuation Passing Style In Common Lisp?

In an effort to find a simple example of CPS which doesn't give me a headache , I came across this Scheme code (Hand typed, so parens may not match) :
(define fact-cps
(lambda(n k)
(cond
((zero? n) (k 1))
(else
(fact-cps (- n 1)
(lambda(v)
(k (* v n))))))))
(define fact
(lambda(n)
(fact-cps n (lambda(v)v)))) ;; (for giggles try (lambda(v)(* v 2)))
(fact 5) => 120
Great, but Scheme isn't Common Lisp, so I took a shot at it:
(defun not-factorial-cps(n k v)
(declare (notinline not-factorial-cps)) ;; needed in clisp to show the trace
(cond
((zerop n) (k v))
((not-factorial-cps (1- n) ((lambda()(setq v (k (* v n))))) v))))
;; so not that simple...
(defun factorial(n)
(not-factorial-cps n (lambda(v)v) 1))
(setf (symbol-function 'k) (lambda(v)v))
(factorial 5) => 120
As you can see, I'm having some problems, so although this works, this has to be wrong. I think all I've accomplished is a convoluted way to do accumulator passing style. So other than going back to the drawing board with this, I had some questions: Where exactly in the Scheme example is the initial value for v coming from? Is it required that lambda expressions only be used? Wouldn't a named function accomplish more since you could maintain the state of each continuation in a data structure which can be manipulated as needed? Is there in particular style/way of continuation passing style in Common Lisp with or without all the macros? Thanks.
The problem with your code is that you call the anonymous function when recurring instead of passing the continuation like in the Scheme example. The Scheme code can easily be made into Common Lisp:
(defun fact-cps (n &optional (k #'values))
(if (zerop n)
(funcall k 1)
(fact-cps (- n 1)
(lambda (v)
(funcall k (* v n))))))
(fact-cps 10) ; ==> 3628800
Since the code didn't use several terms or the implicit progn i switched to if since I think it's slightly more readable. Other than that and the use of funcall because of the LISP-2 nature of Common Lisp it's the identical code to your Scheme version.
Here's an example of something you cannot do tail recursively without either mutation or CPS:
(defun fmapcar (fun lst &optional (k #'values))
(if (not lst)
(funcall k lst)
(let ((r (funcall fun (car lst))))
(fmapcar fun
(cdr lst)
(lambda (x)
(funcall k (cons r x)))))))
(fmapcar #'fact-cps '(0 1 2 3 4 5)) ; ==> (1 1 2 6 24 120)
EDIT
Where exactly in the Scheme example is the initial value for v coming
from?
For every recursion the function makes a function that calls the previous continuation with the value from this iteration with the value from the next iteration, which comes as an argument v. In my fmapcar if you do (fmapcar #'list '(1 2 3)) it turns into
;; base case calls the stacked lambdas with NIL as argument
((lambda (x) ; third iteration
((lambda (x) ; second iteration
((lambda (x) ; first iteration
(values (cons (list 1) x)))
(cons (list 2) x)))
(cons (list 3) x))
NIL)
Now, in the first iteration the continuation is values and we wrap that in a lambda together with consing the first element with the tail that is not computed yet. The next iteration we make another lambda where we call the previous continuation with this iterations consing with the tail that is not computed yet.. At the end we call this function with the empty list and it calls all the nested functions from end to the beginning making the resulting list in the correct order even though the iterations were in oposite order from how you cons a list together.
Is it required that lambda expressions only be used? Wouldn't a named
function accomplish more since you could maintain the state of each
continuation in a data structure which can be manipulated as needed?
I use a named function (values) to start it off, however every iteration of fact-cps has it's own free variable n and k which is unique for that iteration. That is the data structure used and for it to be a named function you'd need to use flet or labels in the very same scope as the anonymous lambda functions are made. Since you are applying previous continuation in your new closure you need to build a new one every time.
Is there in particular style/way of continuation passing style in
Common Lisp with or without all the macros?
It's the same except for the dual namespace. You need to either funcall or apply. Other than that you do it as in any other language.

Variadic Function in Scheme

I have to define a variadic function in Scheme that takes the following form:
(define (n-loop procedure [a list of pairs (x,y)]) where the list of pairs can be any length.
Each pair specifies a lower and upper bound. That is, the following function call: (n-loop (lambda (x y) (inspect (list x y))) (0 2) (0 3)) produces:
(list x y) is (0 0)
(list x y) is (0 1)
(list x y) is (0 2)
(list x y) is (1 0)
(list x y) is (1 1)
(list x y) is (1 2)
Obviously, car and cdr are going to have to be involved in my solution. But the stipulation that makes this difficult is the following. There are to be no assignment statements or iterative loops (while and for) used at all.
I could handle it using while and for to index through the list of pairs, but it appears I have to use recursion. I don't want any code solutions, unless you feel it is necessary for explanation, but does anyone have a suggestion as to how this might be attacked?
The standard way to do looping in Scheme is to use tail recursion. In fact, let's say you have this loop:
(do ((a 0 b)
(b 1 (+ a b))
(i 0 (+ i 1)))
((>= i 10) a)
(eprintf "(fib ~a) = ~a~%" i a))
This actually get macro-expanded into something like the following:
(let loop ((a 0)
(b 1)
(i 0))
(cond ((>= i 10) a)
(else (eprintf "(fib ~a) = ~a~%" i a)
(loop b (+ a b) (+ i 1)))))
Which, further, gets macro-expanded into this (I won't macro-expand the cond, since that's irrelevant to my point):
(letrec ((loop (lambda (a b i)
(cond ((>= i 10) a)
(else (eprintf "(fib ~a) = ~a~%" i a)
(loop b (+ a b) (+ i 1)))))))
(loop 0 1 0))
You should be seeing the letrec here and thinking, "aha! I see recursion!". Indeed you do (specifically in this case, tail recursion, though letrec can be used for non-tail recursions too).
Any iterative loop in Scheme can be rewritten as that (the named let version is how loops are idiomatically written in Scheme, but if your assignment won't let you use named let, expand one step further and use the letrec). The macro-expansions I've described above are straightforward and mechanical, and you should be able to see how one gets translated to the other.
Since your question asked how about variadic functions, you can write a variadic function this way:
(define (sum x . xs)
(if (null? xs) x
(apply sum (+ x (car xs)) (cdr xs))))
(This is, BTW, a horribly inefficient way to write a sum function; I am just using it to demonstrate how you would send (using apply) and receive (using an improper lambda list) arbitrary numbers of arguments.)
Update
Okay, so here is some general advice: you will need two loops:
an outer loop, that goes through the range levels (that's your variadic stuff)
an inner loop, that loops through the numbers in each range level
In each of these loops, think carefully about:
what the starting condition is
what the ending condition is
what you want to do at each iteration
whether there is any state you need to keep between iterations
In particular, think carefully about the last point, as that is how you will nest your loops, given an arbitrary number of nesting levels. (In my sample solution below, that's what the cur variable is.)
After you have decided on all these things, you can then frame the general structure of your solution. I will post the basic structure of my solution below, but you should have a good think about how you want to go about solving the problem, before you look at my code, because it will give you a good grasp of what differences there are between your solution approach and mine, and it will help you understand my code better.
Also, don't be afraid to write it using an imperative-style loop first (like do), then transforming it to the equivalent named let when it's all working. Just reread the first section to see how to do that transformation.
All that said, here is my solution (with the specifics stripped out):
(define (n-loop proc . ranges)
(let outer ((cur ???)
(ranges ranges))
(cond ((null? ranges) ???)
(else (do ((i (caar ranges) (+ i 1)))
((>= i (cadar ranges)))
(outer ??? ???))))))
Remember, once you get this working, you will still need to transform the do loop into one based on named let. (Or, you may have to go even further and transform both the outer and inner loops into their letrec forms.)

How to create a function that multiplies all numbers between 1 and "x" with dotimes?

I'm making a function that multiplies all numbers between an 1 input and a "x" input with dotimes loop. If you please, check my function and say what's wrong since I don't know loops very well in Scheme.
(define (product x)
(let ((result 1))
(dotimes (temp x)
(set! result (* temp (+ result 1))))
result))
Use recursion. It is the way to do things in Scheme/Racket. And try to never use set! and other functions that change variables unless there really is no other choice.
Here's a textbook example of recursion in Scheme:
(define factorial
(lambda (x)
(if (<= x 1)
1
(* x (factorial (- x 1))))))

Resources