Getting tail call optimization in mutual recursion in Scheme - recursion

While developing a classical exercise piece of code for odd and even functions in MIT/GNU Scheme (rel 9.2), I encountered a problem that my code does not terminate for a big integer value.
First, I tested the following code, which processes both positive and negative values:
(define error-message-number "Error. x must be a number")
(define odd?
(lambda (x)
(cond
((not (integer? x)) error-message-number)
((= x 0) #f)
((< x 0) (even? (+ x 1))) ;for negatives
(else (even? (- x 1)))))) ;if number n is odd then n - 1 is even
(define even?
(lambda (x)
(cond
((not (integer? x)) error-message-number)
((= x 0) #t)
((< x 0) (odd? (+ x 1))) ;for negatives
(else (odd? (- x 1)))))) ;if number n is even then n - 1 is odd
The calls (assert (equal? #f (even? 100000000001))) and (assert (equal? #t (odd? -100000000001))) do not terminate on my machine, while, e.g. (assert (equal? #f (even? 1001))) and (assert (equal? #t (odd? -1001))) do.
My first thought was that the code is not optimized for proper tail recursion, while I have not one, but two tail calls in each function.
So, I decided to simplify the task and make a take for positive integers only, like this:
(define error-message-positive "Error. x must be a nonnegative number")
(define odd-positive?
(lambda (x)
(cond
((not (integer? x)) error-message-number)
((= x 0) #f)
((< x 0) error-message-positive) ;for negatives
(else (even? (- x 1)))))) ;if number n is odd then n - 1 is even
(define even-positive?
(lambda (x)
(cond
((not (integer? x)) error-message-number)
((= x 0) #t)
((< x 0) error-message-positive) ;for negatives
(else (odd? (- x 1)))))) ;if number n is even then n - 1 is odd
But this version does not return either for big integers.
So, I have these related questions:
Features. Are mutually recursive functions in MIT/GNU Scheme optimized at all?
Diagnostics. Is there any way one can tell the functions were indeed optimized for mutual tail recursion by Scheme compiler/interpreter. So, how can one tell the problem is in (absence of) tail recursion optimization, or in some other thing.
What is proper mutual tail recursion? Does my initial code qualify for optimization? Does my second take qualify for it?

What is proper mutual tail recursion?
Just like your code, both versions of them.
Diagnostics.
Empirical orders of growth FTW!
Your diagnosis just might be incorrect. In particular, on my machine, in Racket, the expected time of your code to finish is 40 minutes. And it does seem to run in constant memory overall.
Yes, even while running in constant space it still takes time linear in the magnitude of argument. How do I know? I simply measured it in clock wall time, and it indeed scales as linear i.e. n1 power law. Approximately. (i.e. whether it measured as 1.02 or 0.97, it still indicates linear growth rate. approximately. which is all that matters).
See also:
Painter puzzle - estimation
Features. Are mutually recursive functions in MIT/GNU Scheme optimized at all?
It must be so, since tail call optimization is in the language specification. And TCO is more than just tail recursion, as I understand it even if the decision what to call next is dynamic (let alone static, evident in code as it is in your case) it still must run in constant stack space when one tail call eventually leads back to entering the same function again. Tail call is tail call, whatever is called, and it must be optimized. I don't have an official quotation ready at the moment.

Related

Recursion with more than one function

some of you may find this question a little odd, but i really want to know if this program is recursive or not, and that is all I want to know.
(defun howmany(sez)
(if (null sez)
0
(+ 1 (howmany (cdr sez)))))
(defun sum(sez)
(if (null sez)
0
(+ (car sez) (sum(cdr sez)))))
(defun avg(sez)
(if (null sez)
0
(/ (sum sez) (howmany sez))))
(print (avg '(100 200 300)))
Thank for all your answers!
First, take a look at your code and format it a little bit more, in order to be easily read by a lisper
(defun howmany (sez)
(if (null sez)
0
(+ 1 (howmany (cdr sez)))))
(defun sum (sez)
(if (null sez)
0
(+ (car sez) (sum (cdr sez)))))
(defun avg (sez)
(if (null sez)
0
(/ (sum sez) (howmany sez))))
(print (avg '(100 200 300)))
Then analize this script, it contains three functions an a last s-expression which evaluate the functions.
For this three functions, avg, sum and howmany,
There is a story titled Martin and the Dragon, you can find in chapter 8 from here Common Lisp: A Gentle Introduction to Symbolic Computation and you should read, which sumarizes in:
The dragon, beneath its feigned distaste for Martin's questions,
actually enjoyed teaching him about recursion. One day it decided to
formally explain what recursion means. The dragon told Martin to
approach every recursive problem as if it were a journey. If he
followed three rules for solving problems recursively, he would always
complete the journey successfully.
The dragon explained the rules this way:
Know when to stop.
Decide how to take one step.
Break the journey down into that step plus a smaller journey.
Let's see the functions howmany and sum
Know when to stop
it stops when sez is null, i.e. when the list is nil
Decide how to take one step
the if have two ways or 0 for both or
(+ 1 (howmany (cdr sez)))
(+ (car sez) (sum (cdr sez)))
Break the joourney down into that step plus a smaller journey
in the last expressions, the list is smaller take out the first and then continue, with the smaller list
So, this two functions are recursive, the other avg, is not recursive, only take cares of the empty list, in order to prevent dividing by zero or zero/zero indetermination.
Hope this helps

Create a list of binary trees with max height n

A node is a
(define-struct node (left right))
A leafy binary tree (LBT) is one of
; - 'leaf
; - (make-node LBT LBT)
I have to design a function that takes in a natural number n and creates a list of all leafy binary trees that have height n.
So for example, a height of 2 should return:
`(list
(make-node 'leaf (make-node 'leaf 'leaf))
(make-node (make-node 'leaf 'leaf) 'leaf)
(make-node (make-node 'leaf 'leaf) (make-node 'leaf 'leaf)))`
I've been stuck on this assignment for days now. The best I could come up with was:
`(define (lbt-list n)
(cond [(= 0 n) 'leaf]
[(= 1 n) (cons (make-node (lbt-list (- n 1)) (lbt-list (- n 1))) empty)]
[else (list (make-node (first (lbt-list (- n 1))) (lbt-list (- n n)))
(make-node (lbt-list (- n n)) (first (lbt-list (- n 1))))
(make-node (first (lbt-list (- n 1))) (first (lbt-list (- n 1)))))]))`
The problem involves recursion and I'm just not sure how to fully code out this function. Any help would be appreciated!
You are trying to make nodes out of lists; the only valid arguments to make-node are leafs and nodes. Instead, you should take the results of lbt-list and use each of its elements to make each of the nodes for the list to be returned.
Also, you never use the rest of any returned lbt-list.
To start, the reason why you're only getting three trees is that your else clause calls list with exactly three instances of make-node. This might be a little easier to see if you make (= n 1) your base case, and explicitly use 'leaf wherever you need it, instead of (lbt-list (- n n)).
I think you'll benefit from stepping back from the code for a second and asking yourself what mathematical products you're trying to generate. In particular, how do you get the n-depth binary trees from the (n-1)-depth binary trees?
It's simplest to break it into three parts. Here are two big hints:
is make-node commutative?
how is the level-on-level generation related to a Cartesian product?
Finally, helper functions are your friend here - they'll go a long way towards dividing the mental burden of generating the list into smaller pieces. I wrote three helper functions when I threw together a solution, but you might be able to make do with two.

Count amount of odd numbers in a sentence

I am fairly new to lisp and this is one of the practice problems.
First of all, this problem is from simply scheme. I am not sure how to answer this.
The purpose of this question is to write the function, count-odd that takes a sentence as its input and count how many odd digits are contained in it as shown below:
(count-odd'(234 556 4 10 97))
6
or
(count-odd '(24680 42 88))
0
If possible, how would you be able to do it, using higher order functions, or recursion or both - whatever gets the job done.
I'll give you a few pointers, not a full solution:
First of all, I see 2 distinct ways of doing this, recursion or higher order functions + recursion. For this case, I think straight recursion is easier to grok.
So we'll want a function which takes in a list and does stuff, so
(define count-odd
(lambda (ls) SOMETHING))
So this is recursive, so we'd want to split the list
(define count-odd
(lambda (ls)
(let ((head (car ls)) (rest (cdr ls)))
SOMETHING)))
Now this has a problem, it's an error for an empty list (eg (count-odd '())), but I'll let you figure out how to fix that. Hint, check out scheme's case expression, it makes it easy to check and deal with an empty list
Now something is our recursion so for something something like:
(+ (if (is-odd head) 1 0) (Figure out how many odds are in rest))
That should give you something to start on. If you have any specific questions later, feel free to post more questions.
Please take first into consideration the other answer guide so that you try to do it by yourself. The following is a different way of solving it. Here is a tested full solution:
(define (count-odd num_list)
(if (null? num_list)
0
(+ (num_odds (car num_list)) (count-odd (cdr num_list)))))
(define (num_odds number)
(if (zero? number)
0
(+ (if (odd? number) 1 0) (num_odds (quotient number 10)))))
Both procedures are recursive.
count-odd keeps getting the first element of a list and passing it to num_odds until there is no element left in the list (that is the base case, a null list).
num_odds gets the amount of odd digits of a number. To do so, always asks if the number is odd in which case it will add 1, otherwise 0. Then the number is divided by 10 to remove the least significant digit (which determines if the number is odd or even) and is passed as argument to a new call. The process repeats until the number is zero (base case).
Try to solve the problem by hand using only recursion before jumping to a higher-order solution; for that, I'd suggest to take a look at the other answers. After you have done that, aim for a practical solution using the tools at your disposal - I would divide the problem in two parts.
First, how to split a positive integer in a list of its digits; this is a recursive procedure over the input number. There are several ways to do this - by first converting the number to a string, or by using arithmetic operations to extract the digits, to name a few. I'll use the later, with a tail-recursive implementation:
(define (split-digits n)
(let loop ((n n)
(acc '()))
(if (< n 10)
(cons n acc)
(loop (quotient n 10)
(cons (remainder n 10) acc)))))
With this, we can solve the problem in terms of higher-order functions, the structure of the solution mirrors the mental process used to solve the problem by hand:
First, we iterate over all the numbers in the input list (using map)
Split each number in the digits that compose it (using split-digits)
Count how many of those digits are odd, this gives a partial solution for just one number (using count)
Add all the partial solutions in the list returned by map (using apply)
This is how it looks:
(define (count-odd lst)
(apply +
(map (lambda (x)
(count odd? (split-digits x)))
lst)))
Don't be confused if some of the other solutions look strange. Simply Scheme uses non-standard definitions for first and butfirst. Here is a solution, that I hope follows Simply Scheme friendly.
Here is one strategy to solve the problem:
turn the number into a list of digits
transform into a list of zero and ones (zero=even, one=odd)
add the numbers in the list
Example: 123 -> '(1 2 3) -> '(1 0 1) -> 2
(define (digit? x)
(<= 0 x 9))
(define (number->digits x)
(if (digit? x)
(list x)
(cons (remainder x 10)
(number->digits (quotient x 10)))))
(define (digit->zero/one d)
(if (even? d) 0 1))
(define (digits->zero/ones ds)
(map digit->zero/one ds))
(define (add-numbers xs)
(if (null? xs)
0
(+ (first xs)
(add-numbers (butfirst xs)))))
(define (count-odds x)
(add-numbers
(digits->zero/ones
(number->digits x))))
The above is untested, so you might need to fix a few typos.
I think this is a good way, too.
(define (count-odd sequence)
(length (filter odd? sequence)))
(define (odd? num)
(= (remainder num 2) 1))
(count-odd '(234 556 4 10 97))
Hope this will help~
The (length sequence) will return the sequence's length,
(filter proc sequence) will return a sequence that contains all the elements satisfy the proc.
And you can define a function called (odd? num)

Can someone explain how recursion works in these procedures

This is using MIT Scheme, coming from the infamous SICP. I just can't wrap my head around what is happening.
Here's a procedure to compute N!.
(define (factorial n)
(if (= n 0)
1
(* n (factorial (- n 1)))))
Here's a procedure to compute Fibonacci
(define (fib n)
(cond ((= n 0) 0)
((= n 1) 1)
(else (+ (fib (- n 1))
(fib (- n 2))))))
In the SICP book there's a clear, step-by-step explanation of how linear recursion works (for the factorial example), and there's also a good explanation complete with a nice tree diagram detailing tree recursion (for the fibonacci example).
If you need an easier-to-understand explanation of how recursion works in general in a Scheme program, I'd recommend you take a look at either The Little Schemer or How to Design Programs, both books will teach you how to grok recursive processes in general.
Recursion takes some time to understand, so be patient with yourself.
I'd suggest imagining that you were the computer, and stepping through how you would compute (factorial 4). Allow yourself to "be inside" a function multiple times at the same time by thinking of (factorial 4) and (factorial 3) (etc.) as completely different entities.

how many elements on list with scheme

i need to write a function which calculates how many elements on list with scheme language.
for example
(howMany 'a) returns 0
(howMany '(a b)) returns 1
(howMany '(a (b c))) returns 2
how can i do that? i did not want a working code, just only an idea for do that. so maybe you should consider to remove working codes. :) thank you
The fold answers will work. However, if this is homework, you may be trying to do this using only simple built-in functions. There are two possible answers.
Here's the naive way:
(define (howMany list)
(if (null? list)
0
(+ 1 (howMany (cdr list)))
)
)
(Your implementation of Scheme may have a function empty? instead of null?.)
However, this algorithm will take an amount of space linearly proportional to the number of elements in the list, because it will store (+ 1 ...) for each element of the list before doing any of the additions. Intuitively, you shouldn't need this. Here's a better algorithm that avoids that issue:
(define (howMany list)
(define (iter numSoFar restOfList)
(if (null? restOfList)
numSoFar
(iter (+ numSoFar 1) (cdr restOfList))
)
)
(iter 0 list)
)
(Bonus points: use Scheme's (let iter ...) syntax to write this more succinctly. I used this style because it's more clear if you only know a few Scheme primitives.)
This will most likely get down-voted for this phrase, but, I don't know scheme. I am, however, familiar with functional programming.
If there is no built-in for this, start by 'folding' the list with start value of 0 and add 1 on every additional fold.
It is simply counting the number of elements in the list.
(define howMany
(lambda (list)
(cond
[(not (list? list)) 0]
[(null? list) 0]
[else (+ 1 (howMany (cdr list)))])))

Resources