The function is supposed to be tail-recursive and count from 1 to the specified number. I think I'm fairly close. Here's what I have:
(define (countup l)
(if (= 1 l)
(list l)
(list
(countup (- l 1))
l
)
)
)
However, this obviously returns a list with nested lists. I've attempted to use the append function instead of the second list to no avail. Any guidance?
Here's an incorrect solution:
(define (countup n)
(define (help i)
(if (<= i n)
(cons i (help (+ i 1)))
'()))
(help 1))
This solution:
uses a helper function
recurses over the numbers from 1 to n, cons-ing them onto an ever-growing list
Why is this wrong? It's not really tail-recursive, because it creates a big long line of cons calls which can't be evaluated immediately. This would cause a stack overflow for large enough values of n.
Here's a better way to approach this problem:
(define (countup n)
(define (help i nums)
(if (> i 0)
(help (- i 1)
(cons i nums))
nums)))
(help n '()))
Things to note:
this solution is better because the calls to cons can be evaluated immediately, so this function is a candidate for tail-recursion optimization (TCO), in which case stack space won't be a problem.
help recurses over the numbers backwards, thus avoiding the need to use append, which can be quite expensive
You should use an auxiliar function for implementing a tail-recursive solution for this problem (a "loop" function), and use an extra parameter for accumulating the answer. Something like this:
(define (countup n)
(loop n '()))
(define (loop i acc)
(if (zero? i)
acc
(loop (sub1 i) (cons i acc))))
Alternatively, you could use a named let. Either way, the solution is tail-recursive and a parameter is used for accumulating values, notice that the recursion advances backwards, starting at n and counting back to 0, consing each value in turn at the beginning of the list:
(define (countup n)
(let loop ((i n)
(acc '()))
(if (zero? i)
acc
(loop (sub1 i) (cons i acc)))))
Here a working version of your code that returns a list in the proper order (I replaced l by n):
(define (countup n)
(if (= 1 n)
(list n)
(append (countup (- n 1)) (list n))))
Sadly, there is a problem with this piece of code: it is not tail-recursive. The reason is that the recursive call to countup is not in a tail position. It is not in tail position because I'm doing an append of the result of (countup (- l 1)), so the tail call is append (or list when n = 1) and not countup. This means this piece of code is a normal recusrive function but to a tail-recursive function.
Check this link from Wikipedia for a better example on why it is not tail-recusrive.
To make it tail-recursive, you would need to have an accumulator responsible of accumulating the counted values. This way, you would be able to put the recursive function call in a tail position. See the difference in the link I gave you.
Don't hesitate to reply if you need further details.
Assuming this is for a learning exercise and you want this kind of behaviour:
(countup 5) => (list 1 2 3 4 5)
Here's a hint - in a tail-recursive function, the call in tail position should be to itself (unless it is the edge case).
Since countup doesn't take a list of numbers, you will need an accumulator function that takes a number and a list, and returns a list.
Here is a template:
;; countup : number -> (listof number)
(define (countup l)
;; countup-acc : number, (listof number) -> (listof number)
(define (countup-acc c ls)
(if ...
...
(countup-acc ... ...)))
(countup-acc l null))
In the inner call to countup-acc, you will need to alter the argument that is checked for in the edge case to get it closer to that edge case, and you will need to alter the other argument to get it closer to what you want to return in the end.
Related
I can't figure out how can I make this tail recursive Scheme function not tail recursive anymore. Anyone can help me?
(define (foldrecl f x u)
(if (null? x)
u
(foldrecl f (cdr x) (f (car x) u))))
left folds are inheritly iterative, but you can easily make them recursive by adding a continuation. eg.
(let ((value expresion-that-calculates))
value)
So in your case:
(define (foldrecl f x u)
(if (null? x)
u
(let ((result (foldrecl f (cdr x) (f (car x) u))))
result)))
While this looks promising it does not guarantee that a smart Scheme implementation figures out that result is just returned and make it a tail call instead. Right folds are easier since they are inherently recursive:
(define (fold-right proc tail lst)
(if (null? lst)
tail
(proc (car lst)
(fold-right proc tail (cdr lst)))))
Here you clearly see the recursive part needs to become a argument to cons and thus never in tail position unless it is the base case.
Also notice it's slightly simpler to see what arguments goes where when the procedure is called proc, the tail of the result tail and the list argument lst. You don't even need to read my code to know how to use it, but yours I have no idea what x and u and ti doesn't help that the argument order doesn't follow any fold implementations known in Scheme.
The recursive call is in tail position, so put it inside another procedure call like this:
(define (identity x) x)
(define (foldrecl f x u)
(if (null? x)
u
(identity (foldrecl f (cdr x) (f (car x) u)))))
now the recursive call is not in tail position, it is not tail recursive anymore.
A compiler is allowed to optimize away the identity function if it knows that it does nothing but hopefully it wont.
Instead of doing, compose a plan for doing it; only in the end, do:
(define (foldreclr f xs a)
(define (go xs)
(if (null? xs)
(lambda (a) a)
(let ((r (go (cdr xs)))) ; first, recursive call;
(lambda ; afterwards, return a plan:
(a) ; given an a, to
(r ; perform the plan for (cdr xs)
(f (car xs) a)))))) ; AFTER processing (car x) and a.
((go xs) ; when the overall plan is ready,
a)) ; use it with the supplied value
The internal function go follows the right fold pattern. It makes the recursive call first, and only afterwards it composes and returns a value, the plan to first combine the list's head element with the accumulator value, and then perform the plan for the list's tail -- just like the original foldrecl would do.
When the whole list is turned into a plan of action, that action is finally performed to transform the supplied initial accumulator value -- performing the same calculation as the original foldrecl left fold.
This is known as leaning so far right you come back left again.(*)
> (foldreclr - (list 1 2 3 4) 0) ; 4-(3-(2-(1-0)))
2
> (foldreclr - (list 4 3 2 1) 0) ; 1-(2-(3-(4-0)))
-2
See also:
Foldl as foldr
(*) Evolution of a Haskell programmer (fun read)
(sorry, these are in Haskell, but Haskell is a Lisp too.)
I'm studying for a Christmas test and doing some sample exam questions, I've come across this one that has me a bit stumped
I can do regular recursion fine, but I can't wrap my head around how to write the same thing using tail recursion.
Regular version:
(define (factorial X)
(cond
((eqv? X 1) 1)
((number? X)(* X (factorial (- X 1))))))
For a function to be tail recursive, there must be nothing to do after the function returns except return its value. That is, the last thing that happens in the recursive step is the call to the function itself. This is generally achieved by using an accumulator parameter for keeping track of the answer:
(define (factorial x acc)
(if (zero? x)
acc
(factorial (sub1 x) (* x acc))))
The above procedure will be initially called with 1 as accumulator, like this:
(factorial 10 1)
=> 3628800
Notice that the accumulated value gets returned when the base case is reached, and that the acc parameter gets updated at each point in the recursive call. I had to add one extra parameter to the procedure, but this can be avoided by defining an inner procedure or a named let, for example:
(define (factorial x)
(let loop ((x x)
(acc 1))
(if (zero? x)
acc
(loop (sub1 x) (* x acc)))))
I have found the following implementation of the Binary Search in Scheme:
(define (binary-search value vector)
(let helper ((low 0)
(high (- (vector-length vector) 1)))
(if (< high low)
#f
(let ((middle (quotient (+ low high) 2)))
(cond ((> (vector-ref vector middle) value)
(helper low (- middle 1)))
((< (vector-ref vector middle) value)
(helper (+ middle 1) high))
(else middle))))))
according to what it says in the comments, the above function uses tail-recursion to call to the help function. I was wondering if this works like a GOTO instruction, because I do not see that there is a proper "recursive" call to the binary-search function.
In this case it is proper to say that works like a goto instruction?
What you're seeing is called a named let. (I wrote a blog post about how named let works, if you're curious.) The code you have is exactly the same as:
(define (binary-search value vector)
(define (helper low high)
(if (< high low)
#f
(let ((middle (quotient (+ low high) 2)))
(cond ((> (vector-ref vector middle) value)
(helper low (- middle 1)))
((< (vector-ref vector middle) value)
(helper (+ middle 1) high))
(else middle)))))
(helper 0 (- (vector-length vector) 1)))
In other words, it is tail-recursing, on helper rather than on binary-search. But tail recursion is happening.
Some people think of tail-recursion like goto, but I don't consider that a helpful comparison. The only thing in common between the two is that you can implement loops with tail recursion, much like you can do with goto. But the similarities end there: tail-recursion is a special kind of recursion (where the current call frame is replaced with the tail call), but it's still recursion; goto jumps to an arbitrary point in the code, but it's a totally imperative operation with no relation to recursion.
A let is just syntactic sugar for lambdas. So for example:
(let ((i 2)
(j 5)
(* i j))
is equivalent to
((lambda (i j) (* i j)) 2 5)
The let in your code is called a named let, because you provided a label for it. So basically, your lambda in disguise is bound to a name. In that sense, it is a goto. However, you need to be in the scope of the let to be able to "jump" to it. The function is tail recursive because you are not deferring any computations. At any point in time, you only require the current values of i and j to be able to proceed with the computation.
I'm studying for a Christmas test and doing some sample exam questions, I've come across this one that has me a bit stumped
I can do regular recursion fine, but I can't wrap my head around how to write the same thing using tail recursion.
Regular version:
(define (factorial X)
(cond
((eqv? X 1) 1)
((number? X)(* X (factorial (- X 1))))))
For a function to be tail recursive, there must be nothing to do after the function returns except return its value. That is, the last thing that happens in the recursive step is the call to the function itself. This is generally achieved by using an accumulator parameter for keeping track of the answer:
(define (factorial x acc)
(if (zero? x)
acc
(factorial (sub1 x) (* x acc))))
The above procedure will be initially called with 1 as accumulator, like this:
(factorial 10 1)
=> 3628800
Notice that the accumulated value gets returned when the base case is reached, and that the acc parameter gets updated at each point in the recursive call. I had to add one extra parameter to the procedure, but this can be avoided by defining an inner procedure or a named let, for example:
(define (factorial x)
(let loop ((x x)
(acc 1))
(if (zero? x)
acc
(loop (sub1 x) (* x acc)))))
I'm unsure of how to turn count-forwards into a tail-recursive program. It takes a non-negative number, n, and returns the list of integers from 0 to n (including n).
Edit: Okay, I finally got this one to work. The problem wasn't that my current program was recursive and I needed to make it tail-recursive- It was just plain wrong. The actual answer is really short and clean. So if anyone else is stuck on this and is also a total programming noob, here's a few hints that might help:
1) Your helper program is designed to keep track of the list so far.
2) Its base case is.. If x = 0.. what do you do? add 0 onto.. something.
3) Recur on x - 1, and then add x onto your list so far.
4) When you get to your actual program, count-forwards, all you need is the helper. But remember that it takes two arguments!
The only recursive function here is list-reverse. It is tail-recursive, because the call to itself is the last operation in the function body.
Your function for generating a nondecreasing sequence from zero to m, which contains the successive results of adding 1 to the previous element, would look something like:
(define (my-reverse lst)
(define (rev-do xs ys)
(if (empty? xs)
ys
(rev-do (cdr xs) (cons (car xs) ys))))
(rev-do lst empty))
(define (seq m n)
(seq-do m n (list m)))
(define (seq-do m n xs)
(if (= m n)
(my-reverse xs)
(let ((next (add1 m)))
(seq-do next n (cons next xs)))))
(define (seq-from-zero m)
(seq 0 m))
Test:
> (seq-from-zero 10)
(0 1 2 3 4 5 6 7 8 9 10)
seq-do is a general function for generating nondecreasing sequences from m to n; it is tail-recursive, because the last operation is the call to itself.
I've also implemented reverse from scratch, so that you can use it in your homework problems.