Desi Founder @ Work

25 Oct, 2008

Recursion, Misunderstood

Posted by: sharjeel In: Programming

My experience with the Electrical Engineers in academics is that they usually view Computer Science in terms of circuits and details of how things work at the most tangible level. One hazard of using this approach in teaching is that many times you end up with some wrong core concepts of Computer Science. They enable your abstract level thinking at large. The worst part is, you don't even know that your concepts are incorrect yet you are very confident about them.

My undergrad CS program at FAST-NUCES was heavily dominated by dedicated and competent Electrical Engineers. That is why my classmates and I have really good C/C++ programming skills, great concepts about pointers, indepth understanding of microprocessors work, how implementations of Operating Systems take advantage of them at the very nitty gritty level and have strong knowledge of other implementation specific things. On the downside, I feel such students have some gaps left in their personalities towards the mathematical face of Computer Science.

Perhaps the most commonly misunderstood such topic is Recursion. For me, it was a shock to know, after about two years of my graduation, that what I knew about recursion was quite wrong. I, along with many others were taught (and are still being taught) that recursion is about a function calling itself.  When a function calls itself, a separate call is made, the parameters and some other info is placed on stack and a new 'instance' of function takes over until it returns. If this process goes on infinitely, the program would end with an overflowed stack so there must be a base or terminating condition. The instructors would give us assignments in which recursion had to be "removed" by explicitly storing some state information on a stack so that a new call to the same function was not made. The emphasis of these assignments was that although "recursive" code is simple, recursion has a huge overhead which should be removed in most of the cases.

This is not recursion! This way of looking at recursion might be OK for a low-level C/C++ programmer who wants to build his career coding micro-controllers for the rest of his life. But these concepts of recursion are certainly disastrous for a Computer Science Major who wants to truly appreciate the beauty of algorithms.

I was lucky to learn Lisp after my graduation which gave enough abstraction from low level nitty gritty controls such as memory management and pointers as well as complex syntax, to let me focus on the problem itself rather than going into syntax.

What I learnt then is that recursion is solving a problem by deferring until it's subproblem and reconciling the solution of the problem with a simpler computation. The subproblem itself is solved in the same manner until the subproblem becomes so simple that it's solution is trivial. In mathematics, this is called inductive step.

This seems much like the former view but it's implication is quite different. The second definition of recursion implies that a function calling itself may not necessarily be forming a recursive solution. For example the following two implementations of factorial call themselves but the first one is recursive while the second one is iterative:

; Recursive
(define fact
   (lambda (n)
      (if (= n 0) 1
         (* n (factorial (- n 1))))))
 
; Iterative
(define facti
   (lambda (n, c)
      (if (= n 0) c
         (facti (- n 1) (* c n))

The reason facti is not recursive is that it is not deferring any computation.

The equal implementation of these in Python would be:

 
# Recursive
def fact(n):
   if n == 0: return 1
   return n * fact(n - 1)
 
# Iterative
def facti(n, c=1):
   if n == 0: return c
   else: return facti(n - 1, c * n)

Also, a function not calling itself may still be a recursive function. For example, an explicit stack storing different states to avoid function calling itself is still recursive!

PS: If you still don't get what recursion is, see "Recursion, Misunderstood" by Sharjeel Ahmed Qureshi.

13 Responses to "Recursion, Misunderstood"

1 | m

October 25th, 2008 at 11:38 am

Avatar

I don’t completely understand why you discourage the tail-recursive version. Sure, it abstracts from being purely functional, while allowing to predict how the compiled code will work on von Neuman machine (optimisation to while loops).

The dictinction is also important when modeling the problem - tail recursion is useful when the size of accumulated value can be bounded as asymptotically
smaller than the size of the call stack. For example helping to bypass low stack limits.

2 | Stas Shtin

October 25th, 2008 at 12:12 pm

Avatar

Python doesn’t explicitly return last statement. So that’s supposed to be:

# Recursive
def fact(n):
if n == 0:
return 1
return n * fact(n - 1)

# Iterative
def facti(n, c=1)
if n == 0:
return c
else:
return facti(n - 1, c * n)

3 | ben

October 25th, 2008 at 12:58 pm

Avatar

Actually, both definitions are recursive. In fact, the one labeled as iterative is tail recursive, using an accumulator to avoid leaving work to do on the stack. An iterative implementation in Scheme might be

(define (facti n)
(let ((total 1))
(do ((i n))
((<= i 0))
(set! total (* total i))
(set! i (- i 1)))
total))

Cheers.

4 | notyouravgjoel

October 25th, 2008 at 1:04 pm

Avatar

Your iterative solutions are only truly iterative if the language supports tail recursion. Most (all?) functional languages support TCO, and so does gcc (supposedly); but java doesn’t — JVM-based functional languages use various hacks to allow TCO.

AFAIK, python does not support TCO, so if not, the python facti might still kill the stack.

5 | y

October 25th, 2008 at 1:13 pm

Avatar

(define facti
(lambda (n, c)
(if (= n 0) c
(facti (- n 1) (* c n))

This is recursive because it calls itsself.
R5RS has a definition of recursion you should use instead of inventing your own.

6 | Tony Morris

October 25th, 2008 at 2:11 pm

Avatar

“but java doesn’t — JVM-based functional languages use various hacks to allow TCO.”

Bzzt. You mean *Sun* Java implementation. The IBM implementation most certainly supports TCO.

7 | bm

October 25th, 2008 at 3:18 pm

Avatar

ben: iteration doesn’t have to do with syntax. An iterative process is iterative, be the case that you use gotos, for loops or tail calls. Thus, in a language which does tail call optimization, the tail “recursive” version is actually iterative.

8 | Saad

October 25th, 2008 at 5:50 pm

Avatar

Really Sharjeel,

before you make big statements like this in future, go and read Programming Languages. Also, Lisp is a TERRIBLE choice to demonstrate your point if you are aiming at a somewhat wider audience.

9 | rpdillon

October 25th, 2008 at 10:17 pm

Avatar

OP is in no way “inventing his own” definition of recursion, as y implied. As bm said, recursion is a property of the behavior of the algorithm, not an artifact of how that behavior is described.

As I said in the Reddit thread on this topic, if you’d like some background on what sharjeel is talking about, check section 1.2.1 in SICP, where it is made quite clear that the behavior of an algorithm as quite distinct from it’s description.

10 | Ned Batchelder

October 25th, 2008 at 10:35 pm

Avatar

You might want to read Structure and Interpretation of Computer Programs, section 1.2.1. There they make a clear distinction between recursive processes and recursive procedures. By their definition, both your fact and facti are recursive procedures. But fact is a recursive process and facti is an iterative process.

To quote them:

“In contrasting iteration and recursion, we must be careful not to confuse the notion of recursive process with the notion of a recursive procedure. When we describe a procedure as recursive, we are referring to the syntactic fact that the procedure [calls] itself. But when we describe a process [as recursive], we are speaking about how the process evolves, not about the syntax of how a procedure is written.”

11 | ben

October 26th, 2008 at 1:53 am

Avatar

bm: I went and read section 1.2.1 of SICP as recommended in the reddit comments and the distinction between forms of functions and processes makes more sense now. Thanks to you and Sharjeel for a most profitable morning :)

The paragraph that I found most enlightening was

The contrast between the two processes can be seen in another way. In the iterative case, the program variables provide a complete description of the state of the process at any point. If we stopped the computation between steps, all we would need to do to resume the computation is to supply the interpreter with the values of the three program variables. Not so with the recursive process. In this case there is some additional “hidden” information, maintained by the interpreter and not contained in the program variables, which indicates “where the process is” in negotiating the chain of deferred operations. The longer the chain, the more information must be maintained.

12 | sharjeel

October 27th, 2008 at 4:15 pm

Avatar

@m:
I’m not discouraging, I’m just making a distinction to make things clear.

@Stas Shtin:
Thanks for pointing out. I hastly wrote the code earlier. I’ve updated it now.

@ben, notyouravgjoel
You are right in your own perspective but I’m viewing it from language agnostic point of view.

@y:
Can you please be more specific to englighten me

@Ned Batchelder:
Thanks for enlighting everyone.

13 | Recursion, Misunderstood

December 15th, 2008 at 11:36 am

Avatar

[…] If you still don’t get what recursion is, see “Recursion, Misunderstood” by Sharjeel Ahmed Qureshi. […]

Comment Form


  • Meher: Hi I could deduce from your comment on weather about your interaction with machines.We are so geared and programmed to think in context and in directi
  • Adnan: MS Office is good? I think you have not tried OO as yet. :-) and I also like Windows Mobile. The other two cool products by MS are Windows Live Wri
  • Recursion, Misunderstood: [...] If you still don’t get what recursion is, see “Recursion, Misunderstood” by Sharjeel Ahmed Qureshi. [...]

Flickr PhotoStream

    HTC TyTN II HTC TyTn II Keyboard Closeup Happy Time Kids Playing on a bench Nasi Goreng Ice Cream Burger King Fries Whopper Cunning Cat 

About

Desi Founder @ Work. A Pakistani tech entrepreneur's journal