Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do recursion in anonymous fn, without tail recursion

Tags:

How do I do recursion in an anonymous function, without using tail recursion?

For example (from Vanderhart 2010, p 38):

(defn power   [number exponent]   (if (zero? exponent)     1     (* number (power number (- exponent 1))))) 

Let's say I wanted to do this as an anonymous function. And for some reason I didn't want to use tail recursion. How would I do it? For example:

( (fn [number exponent] ......))))) 5 3) 125 

Can I use loop for this, or can loop only be used with recur?

like image 216
Sonia Hamilton Avatar asked May 07 '12 23:05

Sonia Hamilton


People also ask

How do you use recursion in anonymous functions?

Anonymous recursion primarily consists of calling "the current function", which results in direct recursion. Anonymous indirect recursion is possible, such as by calling "the caller (the previous function)", or, more rarely, by going further up the call stack, and this can be chained to produce mutual recursion.

What is non-tail recursion?

Non-Tail / Head Recursion A function is called the non-tail or head recursive if a function makes a recursive call itself, the recursive call will be the first statement in the function. It means there should be no statement or operation is called before the recursive calls.

Which is better tail or non-tail recursion?

The tail recursion is better than non-tail recursion. As there is no task left after the recursive call, it will be easier for the compiler to optimize the code. When one function is called, its address is stored inside the stack. So if it is tail recursion, then storing addresses into stack is not needed.


2 Answers

The fn special form gives you the option to provide a name that can be used internally for recursion.

(doc fn) ;=> (fn name? [params*] exprs*) 

So, add "power" as the name to complete your example.

(fn power [n e]   (if (zero? e)     1     (* n (power n (dec e))))) 

Even if the recursion happened in the tail position, it will not be optimized to replace the current stack frame. Clojure enforces you to be explicit about it with loop/recur and trampoline.

like image 101
Jeremy Avatar answered Sep 20 '22 05:09

Jeremy


I know that in Clojure there's syntactic support for "naming" an anonymous function, as other answers have pointed out. However, I want to show a first-principles approach to solve the question, one that does not depend on the existence of special syntax on the programming language and that would work on any language with first-order procedures (lambdas).

In principle, if you want to do a recursive function call, you need to refer to the name of the function so "anonymous" (i.e. nameless functions) can not be used for performing a recursion ... unless you use the Y-Combinator. Here's an explanation of how it works in Clojure.

Let me show you how it's used with an example. First, a Y-Combinator that works for functions with a variable number of arguments:

(defn Y [f]   ((fn [x] (x x))    (fn [x]        (f (fn [& args]               (apply (x x) args)))))) 

Now, the anonymous function that implements the power procedure as defined in the question. Clearly, it doesn't have a name, power is only a parameter to the outermost function:

(fn [power]       (fn [number exponent]           (if (zero? exponent)               1               (* number (power number (- exponent 1)))))) 

Finally, here's how to apply the Y-Combinator to the anonymous power procedure, passing as parameters number=5 and exponent=3 (it's not tail-recursive BTW):

((Y    (fn [power]       (fn [number exponent]           (if (zero? exponent)               1               (* number (power number (- exponent 1)))))))  5 3)  > 125 
like image 31
Óscar López Avatar answered Sep 20 '22 05:09

Óscar López