46

I wondered whether a while loop is intrinsically a recursion?

I think it is because a while loop can be seen as a function that calls itself at the end. If it is not recursion, then what is the difference?

Peter Mortensen
  • 1,050
  • 2
  • 12
  • 14
badbye
  • 585
  • 1
  • 4
  • 5
  • 1
    Possible duplicate of [General Way to convert a loop (while/for) to recursion or from a recursion to a loop?](http://programmers.stackexchange.com/questions/279004/general-way-to-convert-a-loop-while-for-to-recursion-or-from-a-recursion-to-a) – gnat Jul 24 '16 at 10:02
  • 13
    You can convert recursion to iteration and vice versa, yes. That doesn't mean they are the same, they just have the same capabilities. There are times when recursion is more natural, and there are times where iteration is more natural. – Polygnome Jul 24 '16 at 13:36
  • 1
    @Polygnome: Not always. A function that calls itself twice is recursive, but cannot necessarily be converted to iteration without becoming a different algorithm. – Mooing Duck Jul 24 '16 at 18:00
  • 18
    @MooingDuck You can prove by induction that any recursion can be written as iteration and vice versa. Yes, it will look very different, but you can do it nonetheless. – Polygnome Jul 24 '16 at 18:17
  • @Polygnome: I wouldn't say "can be written as" so much as "can be converted to". And some (few) of those conversions look so wildly different that you'd be hard pressed to convince someone that they're the same algorithm. I'm having a hard time imagining what a iterative Fibonacci generator would look like using the recursive algorithm. – Mooing Duck Jul 24 '16 at 22:57
  • 1
    Semantic argument guys. The principle is correct - conversion is possible. This all avoids answering the question. – quickly_now Jul 25 '16 at 03:04
  • The machine code between the two is different. Just pointing that out. – user64742 Jul 25 '16 at 04:34
  • 6
    What does *intrinsically same* mean here? In programming, using recursion means a specific thing, which is different from iteration (loops). In CS, when you get closer to the theoretical maths side of things, these things start to mean a bit different things. – hyde Jul 25 '16 at 07:19
  • The key concept here is "tail recursion". – John R. Strohm Jul 25 '16 at 07:21
  • @Giorgio They are not the same thing, neither in practice nor in CS. They have fundamentally different approaches to a similar problem, and they have the same expressability (you can write the same functionality using them), but they approach the problem from very different sides. – Polygnome Jul 25 '16 at 07:51
  • 3
    @MooingDuck The conversion from recursive to iterative is actually pretty trivial. You just keep a stack of function-call parameters and a stack of resultsfor the function calls. You replace the recursive calls by adding the parameters to the call stack. sure there's all the handling of the stack that breaks a bit the structure of the algorithm, but once you understand this is quite easy to see that the code does the same thing. Basically you are explicitly writing the call stack that is implicit in the recursive definitions. – Bakuriu Jul 25 '16 at 17:50
  • As you can see, the answer to your question depends on what your intended context is. In the 'language of mathematical recursion theory' context, the answer is yes *(see 'mu-recursion' reply)*. From the 'actual implementation in a programming language' context, the answer depends on which programming language, or language style, you pick *(see other replies)*. I think the way you phrase your 'yes?' arguments in the question suggest the best fit for you is the 'recursion theory' reply. Perhaps it would help to research exactly what the word 'recursion' *originally meant* back when it was introd –  Jul 24 '16 at 22:28
  • Note that a recursively-defined procedure that does not require a stack is actually an iterative process. – gardenhead Jul 25 '16 at 20:10
  • @Polygnome Not all recursive functions can be converted to an iterative form. For example, the [Ackermann Function](http://www.youtube.com/watch?v=i7sm9dzFtEI&sns=em). This doesn't mean you can't implement a simple machine using e.g. std::stack and a loop, but in that case the simple machine is still computing the function recursively, even if the host code uses a loop at the top level to run the machine. – MooseBoys Jul 25 '16 at 21:04
  • @MooseBoys see http://try.haxe.org/#1b818 Ackerman function, once recursive, once iterative. Computability theory, especially the Church-Turing thesis, has long established that recurson and iteration are equally experssive. Not sure why you would question such a simple fact. Implementing a data structure that we call a "stack" does not mean its no longer iterative - it is! The call stack used by programming languages is an implementation detail and has little to do with the fact what recursion and iteration actually *is*. – Polygnome Jul 25 '16 at 21:12
  • While loops don't add to the call stack – Daniel M. Jul 25 '16 at 23:16
  • @badbye, The answer might depend on what you mean by "recursion". Mathematicians use that word, computer scientists use it, and software developers use it. And, both mathematicians and computer scientists use it in more than one way. A couple of the answers below touch on the math/CS usage which mostly talk about _definitions_. The other answers all come from software development which is mostly concerned with _implementations_. Search Wikipedia for "recursive" and "recursion" and you'll find more than a few different pages. – Solomon Slow Jul 26 '16 at 13:35
  • 1
    'The machine code between the two is different. Just pointing that out.' Not necessarily. A good compiler may apply tail-recursion optimization and generate exactly the same code for `while A do B` as for `let f() = if A then (B;f()) ; f()`. – Theodore Norvell Jul 26 '16 at 15:11
  • @TheGreatDuck if the compiler has tail-call-optimisation, then it could generate the same machine-code for recursion, as it does for iteration (@danielM as tail-call-optimisation avoids adding to the call stack). However they are different ideas. That is they are different in the abstract, but may be identical at the concrete. – ctrl-alt-delor Apr 08 '17 at 22:05

11 Answers11

123

Loops are very much not recursion. In fact, they are the prime example of the opposite mechanism: iteration.

The point of recursion is that one element of processing calls another instance of itself. The loop control machinery merely jumps back to the point where it started.

Jumping around in code and calling another block of code are different operations. For instance, when you jump to the start of the loop, the loop control variable still has the same value it had before the jump. But if you call another instance of the routine you're in, then the new instance has new, unrelated copies of all of its variables. Effectively, one variable can have one value on the first level of processing and another value on a lower level.

This capability is crucial for many recursive algorithms to work, and this is why you can't emulate recursion via iteration without also managing a stack of called frames which keeps track of all those values.

Kilian Foth
  • 107,706
  • 45
  • 295
  • 310
  • 2
    "The loop control machinery merely jumps back to the point where it started.": Merely jumps back? When a new iteration is started, the state of the system has been changed by the loop's body. This is exactly what recursion does: call itself with new arguments. – Giorgio Jul 24 '16 at 07:47
  • "Jumping around in code": The `while` loop has much more structure than arbitrarily _jumping around in code_ for which there is the `goto` statement. – Giorgio Jul 24 '16 at 07:49
  • 10
    @Giorgio That may be true, but it's a comment on a claim the answer didn't make. "Arbitrarily" is not present in this answer and would significantly changes the meaning. – hvd Jul 24 '16 at 11:43
  • 3
    @KilianFoth How does tail recursion fit in here? Based on this answer, I would think you do not consider that recursion at all. Is that correct? – hvd Jul 24 '16 at 11:44
  • @hvd: The adverb "arbitrarily" does not add any information, it only makes the statement of the answer explicit. "Jumping around in code" is what `goto` does. `while` is a very special way of jumping around in code with a specific structure. This extra structure is glossed over by saying that `while` corresponds to jumping around in code. – Giorgio Jul 24 '16 at 13:50
  • 13
    @hvd In principle, tail recursion is full recursion like any other. Intelligent compilers can optimize away the actual "creating a new stack frame" part so that the generated code is very similar to a loop, but the concepts we're talking about apply to the source code level. I consider the form an algorithm has *as source code* the important thing, so I'd still call it recursion – Kilian Foth Jul 24 '16 at 15:56
  • 5
    @KilianFoth That makes sense for e.g. C, but tail calls in some languages are not a compiler optimisation, but a feature of the language. One well-known language which mandates it in some cases is the current version of JavaScript/ECMAScript. Your logic doesn't really hold when they are not a compiler optimisation, when the language specifies the behaviour without a call/return construct. – hvd Jul 24 '16 at 16:24
  • 15
    @Giorgio "this is exactly what recursion does: call itself with new arguments" — except for the call. And the arguments. – hobbs Jul 24 '16 at 18:34
  • 5
    @hobbs +1, and the independent, coexistent copies of all other local variables. Sometimes I wonder if people actually read answers before trying to be smart pedants underneath them. – underscore_d Jul 24 '16 at 22:04
  • 4
    You are all looking at implementation details and overlooking the underlying abstract concepts. – Giorgio Jul 25 '16 at 04:36
  • 2
    "except for the call. And the arguments": Incorrect: all variables used in a while loop are the implicit arguments to the new recursive call. Look at the abstract concepts not at implementation details. Abstraction, you know, is the basis of programming. – Giorgio Jul 25 '16 at 04:41
  • 12
    @Giorgio You are using diffferent definitions of words than most here. Words, you know, are the basis of communication. This is Programmers, not CS Stack Exchange. If we used words like "argument", "call", "function" etc the way you suggest, it would be impossible to discuss about actual code. – hyde Jul 25 '16 at 09:29
  • 4
    @hvd Not really. Tail call optimization is all about "how do I run a recursive algorithm on a modern CPU effectively"? There's nothing tail calls give you on their own - conceptually, they're a recursive call like any other. The fact that they make TCO trivial is their only important feature, AFAIK, and that's an implementation detail. An important detail, to be sure, since they allow you to maintain the illusion that you can recurse infinitely (just like GC allows you to maintain the illusion that memory is infinite), but an implementation detail nonetheless. – Luaan Jul 25 '16 at 10:03
  • 2
    @Luaan When TCO is mandated by the language, it's not an illusion, since you have a hard guarantee that you can recurse without being bounded by the stack size, and it's not an implementation detail since it doesn't depend on which implementation you're using. – hvd Jul 25 '16 at 10:56
  • 6
    @Giorgio I am looking at the abstract concept. There's the concept where you recur and the concept where you loop. They're *different* concepts. Hobbs is 100% correct that there are no arguments and there is no call. They are fundamentally and abstractly different. And that's good because they solve different problems. You, on the other hand, are looking at how you might implement loops when your only tool is recursion. Ironic you're telling Hobbs to stop thinking about implementation and start looking at concepts when your methodology is the one that really needs the reassessment. – corsiKa Jul 25 '16 at 15:13
  • 2
    That's not what "opposite" means, and I don't know that the concept of an opposite even makes sense with program control structures. Perhaps with "goto" and "camefrom" ... – T.E.D. Jul 25 '16 at 16:11
  • 2
    I don't think it's correct to say that iteration is the "opposite" of recursion. They are actually very close to being the same thing. – Dave Cousineau Jul 25 '16 at 16:54
  • 1
    @Giorgio "When a new iteration is started, the state of the system has been changed by the loop's body. This is exactly what recursion does: call itself with new arguments." Your argument amounts to "everything loops do is something recursion does". But with recursion, things can be done that can't be done with only loops. "Every A is a B" does not mean "A and B mean the same". – Rosie F Jul 25 '16 at 17:04
  • @corsiKa they are not "fundamentally and abstractly different"; they are actually two versions of the same thing. they have differences, but they're actually "fundamentally equivalent", not "fundamentally different". – Dave Cousineau Jul 25 '16 at 19:01
  • even saying "Jumping around in code and calling another block of code are different operations." is just wrong. calling another block of code *is* "jumping around in code", the only difference being whether you saved something on a stack first or not. in some assembly languages, there's literally no difference aside from what you do or do not choose to save on the stack before jumping. – Dave Cousineau Jul 25 '16 at 19:04
  • 1
    @Sahuagin no, they aren't fundamentally equivilent. Through clever tricks you can force one of them to be like the other. I can pound nails with an axe by flipping it over, and I can chop wood with a hammer (done it, unfortunately) but that doesn't mean they're the same thing even though I can force them to do the same things. – corsiKa Jul 25 '16 at 19:06
  • @corsiKa I guess I am getting stuck on "iteration with a stack" VS recursion, which are fundamentally equivalent. but you are right that regular iteration VS recursion are not equivalent. – Dave Cousineau Jul 25 '16 at 19:40
  • 1
    @Sahuagin: The OP did not ask whether the `while` loop is equivalent to recursion. They asked whether the `while` loop is a form of recursion: it is not symmetric, it is only in one direction. – Giorgio Jul 25 '16 at 21:56
42

This depends on your point of view.

If you look at computability theory, then iteration and recursion are equally expressive. What this means is that you can write a function that computes something, and it doesn't matter whether you do it recursively or iteratively, you will be able to choose both approaches. There is nothing you can compute recursively which you can not compute iteratively and vice versa (although internal workings of the program might be different).

Many programming languages don't treat recursion and iteration the same, and for good reason. Usually, recursion means that the language/compiler handles the call stack, and iteration means you might have to do stack-handling yourself.

However, there are languages -- especially functional languages -- in which things like loops (for, while) are indeed only syntactic sugar for recursion and implemented behind the scenes that way. This is often desirable in functional languages, because they usually don't have the concept of looping otherwise, and adding it would make their calculus more complex, for little practical reason.

So no, they are not intrinsically the same. They are equally expressive, meaning you can not compute something iteratively you can't compute recursively and vice versa, but that's about it, in the general case (according to the Church-Turing thesis).

Note that we are talking about recursive programs here. There are other forms of recursion, e.g. in data structures (e.g. trees).


If you look at it from an implementation point of view, then recursion and iteration are pretty much not the same. Recursion creates a new stack frame for every call. Every step of the recursion is self-contained, getting the arguments for the computation from the callee (itself).

Loops on the other hand don't create call frames. For them, the context is not preserved on each step. For the loop, the program merely jumps back to the start of the loop until the loop condition fails.

This is quite important to know, since it can make pretty radical differences in the real world. For recursion, the whole context has to be saved on every call. For iteration, you have precise control about what variables are in memory and what is saved where.

If you look at it that way, you quickly see that for most languages, iteration and recursion are fundamentally different and have different properties. Depending on the situation, some of the properties are more desirable then others.

Recursion can make programs more simple and easier to test and proof. Converting a recursion to iteration usually makes the code more complex, increasing the likelihood for failure. On the other hand, converting to iteration and reducing the amount of call stack frames can save much needed memory.

Uyghur Lives Matter
  • 126
  • 1
  • 1
  • 10
Polygnome
  • 2,039
  • 15
  • 15
  • A language with local variables and recursion but no arrays could perform tasks which could not be performed by an iterative language with local variables and no arrays. For example, report whether an input contains an alphanumeric string of unknown length followed by a blank and then the characters of the original string in reverse order. – supercat Jul 25 '16 at 15:29
  • 3
    As long as the language is turing complete, it can. An array can easily be replaced by a (doubly) linked list, for example. Talking about iteration or recursion and wether they are equal only makes sense if you compare two turing-complete languages. – Polygnome Jul 25 '16 at 15:33
  • I meant having nothing other than simple static or automatic variables, i.e. *not* being Turing-complete. A purely-iterative language would be limited to those tasks that can be accomplished via simple deterministic finite automaton, while a recursive language would add the ability to perform tasks that would require at least a pushdown deterministic finite automaton. – supercat Jul 25 '16 at 16:01
  • 1
    If the language isn't turing complete, its pointless to begin with. DFAs can neither do arbitrary iteration nor recursion btw. – Polygnome Jul 25 '16 at 16:17
  • 2
    No implementation is actually Turing-complete, and languages which are not Turing-complete can be useful for many purposes. Any program that can be run with a a finite number of variables with a finite range can be accommodated by a DFA where every possible combination of values is a discrete state. – supercat Jul 25 '16 at 16:45
  • In tail call cases, where the arguments of the previous recursion can share space with the next one and the return value is the same, ends up with no call frames and yet still is recursion. So the "call frame" argument isn't airtight. – Yakk Jul 25 '16 at 17:19
  • @supercat Most implementations are turing-complete. The only exception is tht many languages don't have infinite data structures, but thats not relevant from a practical point of view. I am not saying that languages that aren't turing complete can't be useful, but in order to compare something you have to compare the same thing. The Church-Turing thesis establishes the expressiveness and relationship between recursion and iteration. – Polygnome Jul 25 '16 at 21:00
  • @Yakk I realize that the call frame argument isn't airtight, but that is an implementation detail (when done by the compiler). And if you rewrite from "normal" recursion to tail recursion manually you are doing a transformation anyways. I did not want to get into specific regarding tail-end recursion, because optimizations in that regard depend on the compiler and I wanted to stay in the genaral case, and the answer is long enough already. Furthermore I don't think it adds much clarity in regards to answering the original question. – Polygnome Jul 25 '16 at 21:02
  • @Polygnome: Languages which would be Turing-complete on implementations with unlimited dynamic storage can accomplish a wider variety of tasks than those which are fundamentally not Turing-complete, but non-Turing-complete languages may be superior for some purposes. Among other things, in a non-Turing-complete language it may be possible to quickly establish, for any given program, what its worst-case time and resource requirements will be, while in the general case that will be impossible for Turing-complete languages. – supercat Jul 25 '16 at 21:08
  • @supercat Yes? That is absolutely true. But I am not sure where you are getting at? – Polygnome Jul 25 '16 at 21:14
  • @Polygnome: There exist languages which are not Turing-complete but are useful for various purposes. Adding recursion to such a language will increase the variety of tasks it can perform, but will make it harder to make guarantees about program behavior. – supercat Jul 25 '16 at 21:24
  • @supercat Yes, but whats that have to do with the original question? – Polygnome Jul 25 '16 at 23:48
37

Saying that X is intrinsically Y only makes sense if you've got some (formal) system in mind that you are expressing X in. If you define the semantics of while in terms of the lambda calculus, you might mention recursion*; if you define it in terms of a register machine, you probably won't.

In either case, people probably won't understand you if you call a function recursive just because it contains a while loop.

* Though perhaps only indirectly, for example if you define it in terms of fold.

Cactus Golov
  • 875
  • 7
  • 13
  • 4
    To be fair, the function isn't recursive in any definition. It just contains an recursive element, the loop. – Luaan Jul 25 '16 at 10:04
  • @Luaan: Definitely so, but since in languages with a `while` construct recursivity is generally a property of functions, I just can't think of anything else to describe as "recursive" in this context. – Cactus Golov Jul 26 '16 at 17:43
13

The difference is the implicit stack and semantic.

A while loop that "calls itself at the end" has no stack to crawl back up when it's done. It's last iteration sets what state will be as it ends.

Recursion however can't be done without this implicit stack that remembers the state of work done before.

It is true that you can solve any recursion problem with iteration if you give it access to a stack explicitly. But doing it that way is not the same.

The semantic difference has to do with the fact that looking at recursive code conveys an idea in a completely different way than iterative code. Iterative code does things a step at a time. It accepts whatever state that came from before and only works to create the next state.

Recursive code breaks a problem into fractals. This little part looks like that big part so we can do just this bit of it and that bit of it the same way. It's a different way to think about problems. It's very powerful and takes getting used to. A lot can be said in a few lines. You just can't get that out of a while loop even if it has access to a stack.

candied_orange
  • 102,279
  • 24
  • 197
  • 315
  • 5
    I think "implicit stack" is misleading. Recursion is part of a language's semantics, not an implementation detail. (Granted, *most* recursion-supporting languages use a call stack; but firstly, a few such languages don't, and secondly, even in languages that do, not every recursive call necessarily appends to the call stack, since many languages support optimizations such as *tail call elimination*.) Understanding the usual/simple implementation can be useful in getting a handle on the abstraction, but you shouldn't trick yourself into thinking it's the whole story. – ruakh Jul 25 '16 at 02:45
  • 2
    @ruakh I would argue a function that executes in constant space by using tail call elimination really is a loop. Here the stack isn't the implementation detail, it's the abstraction that allows you to accumulate different states for different levels of recursion. – Cimbali Jul 25 '16 at 12:05
  • @ruakh: any state within a single recursive call will be stored on an implicit stack, unless the recursion can be converted by the compiler into a iterative loop. The tail call elimination **is** an implementation detail, the one which you need to be aware of if you want to reorganize your function to be tail-recursive. Also, *"few such languages don't"* - can you provide an example of languages which don't need a stack for recursive calls? – vgru Jul 26 '16 at 11:10
  • 1
    @Groo: See https://en.wikipedia.org/wiki/Continuation-passing_style. – ruakh Jul 26 '16 at 14:20
  • @ruakh: CPS by itself creates the same implicit stack, so it must rely on tail call elimination to make sense (which it makes trivial due to way it's constructed). Even the wikipedia article you linked to says the same: *Using CPS without tail call optimization (TCO) will cause not only the constructed continuation to potentially grow during recursion, but also the call stack*. – vgru Jul 26 '16 at 15:42
8

It all hinges on your use of the term intrinsically. On the programming language level, they are syntactically and semantically different, and they have quite different performance and memory use. But if you dig deep enough into theory they can be defined in terms of each other, and is therefore "the same" in some theoretical sense.

The real question is: When does it makes sense to distinguish between iteration (loops) and recursion, and when is it useful to think of it as the same things? The answer is that when actually programming (as opposed to writing mathematical proofs) it is important to distinguish between iteration and recursion.

Recursion creates a new stack frame, i.e. a new set of local variables for each call. This has overhead, and takes up space on the stack, which means that a deep enough recursion may overflow the stack which causes the program to crash. Iteration on the other hand only modifies the existing variables so is generally faster and only takes up a constant amount of memory. So this is a very important distinction for a developer!

In languages with tail-call recursion (typically functional languages), the compiler may be able to optimize recursive calls in such a way that they only takes up a constant amount of memory. In those languages the important distinction is not iteration vs recursion, but non-tail-call-recursion version tail-call-recursion and iteration.

Bottom line: You need to be able to tell the difference, otherwise your program will crash.

JacquesB
  • 57,310
  • 21
  • 127
  • 176
4

while loops are a form of recursion, see e.g. the accepted answer to this question. They correspond to the μ-operator in computability theory (see e.g. here).

All variations of for loops that iterate on a range of numbers, a finite collection, an array, and so on, correspond to primitive recursion, see e.g. here and here. Note that the for loops of C, C++, Java, and so on, are actually syntactic sugar for a while loop, and therefore it does not correspond to primitive recursion. The Pascal for loop is an example of primitive recursion.

An important difference is that primitive recursion always terminates, whereas generalized recursion (while loops) may not terminate.

EDIT

Some clarifications regarding comments and other answers. "Recursion occurs when a thing is defined in terms of itself or of its type." (see wikipedia). So,

Is a while loop intrinsically a recursion?

Since you can define a while loop in terms of itself

while p do c := if p then (c; while p do c))

then, yes, a while loop is a form of recursion. Recursive functions are another form of recursion (another example of recursive definition). Lists and trees are other forms of recursion.

Another question that is implicitly assumed by many answers and comments is

Are while loops and recursive functions equivalent?

The answer to this question is no: A while loop corresponds to a tail-recursive function, where variables that are accessed by the loop correspond to the arguments of the implicit recursive function, but, as others have pointed out, non-tail-recursive functions cannot be modeled by a while loop without using an extra stack.

So, the fact that "a while loop is a form of recursion" does not contradict the fact that "some recursive functions cannot be expressed by a while loop".

Giorgio
  • 19,486
  • 16
  • 84
  • 135
  • What do you mean by "primitive" recursion? If a for loop is syntactic sugar of a while loop which is a form of recursion. Isn't for loops really also a form of recursion? – lightning_missile Jul 24 '16 at 08:36
  • @morbidCode: As I explained above, I mean a Pascal `for` loop, or any loop that iterates on a finite collection, e.g. the `each` method on Ruby arrays. In these examples, the loop is not syntactic sugar for a `while` loop. On the other hand, the C, C++, Java `for` loops are **not** an example of primitive recursion. Primitive recursion means that the maximum number of iterations / recursion depth is fixed before starting the loop. – Giorgio Jul 24 '16 at 08:46
  • @morbidCode By `for` loops we actually mean so called `for-each` loops. Sure, given that `while` loops are more general *all* loops can be seen as syntactic sugar for `while` loops, but for each loops repersent a specific subset of such loops which are not general enough to reproduce all possible recursions. – Bakuriu Jul 24 '16 at 09:50
  • 2
    @morbidCode: primitive recursion and μ-recursion are forms of recursion with specific restrictions (or lack thereof), studied e.g. in computability theory. As it turns out, a language with just a `FOR` loop can compute exactly all primitive recursive functions, and a language with just a `WHILE` loop can compute exactly all µ-recursive functions (and it turns out that the µ-recursive functions are exactly those functions that a Turing Machine can compute). Or, to make it short: primitive recursion and µ-recursion are technical terms from maths / computability theory. – Jörg W Mittag Jul 24 '16 at 11:49
  • 2
    I thought "recursion" implied a function calling itself, resulting in the current execution state being pushed to the stack and so on; therefore most machines have a practical limit on how many levels you can recurse. While loops don't have any such limits because they internally would use something like a "JMP" and don't use the stack. Just my understanding, could be wrong. – Jay Jul 24 '16 at 13:53
  • @Jayraj: It depends on whether you need to keep the execution state for future use. If you do, you can use a recursive function call or a while loop with an extra stack you have to manage yourself. In this case, even a while loop is limited by the amount of memory you can use for the stack. If you do not need to keep the old execution state, e.g. if you are adding up the numbers in a list, you can use a tail-recursive function with TCO (not supported by all languages) or a plain while loop. In this case, you can have millions or recursive calls resp. iterations without running out of memory. – Giorgio Jul 24 '16 at 14:02
  • But if a `for` loop is primitive, and primitive recursion always terminates, then what about `for(;;;)`? This will be an unterminated recursion and it can presumably be done in Pascal (I dont know the syntax) – David says Reinstate Monica Jul 24 '16 at 16:08
  • 13
    This answer is using a _completely_ different definition for the word "recursive" than the OP was using, and is thus highly misleading. – Mooing Duck Jul 24 '16 at 18:05
  • 2
    @DavidGrinberg: Quoting: "the C, C++, Java for loops are not an example of primitive recursion. Primitive recursion means that the maximum number of iterations / recursion depth is fixed before starting the loop." Giorgio is talking about _Computability theory_ primitives. Unrelated to programming languages. – Mooing Duck Jul 24 '16 at 18:08
  • 3
    I have to agree with Mooing Duck. While computability theory might be interesting in theoretical CS, I think everyone agrees that the OP was talking about the programming languages concept. – Voo Jul 24 '16 at 19:30
  • @MooingDuck: "...Computability theory primitives. Unrelated to programming languages." Huh???!!! – Giorgio Jul 25 '16 at 04:38
  • @MooingDuck: `while p do c` is the same as `if p then (c; while p do c))`, how is this **not** recursive? – Giorgio Jul 25 '16 at 04:46
  • @Giorgio: "recursion is... a function being defined is applied within its own definition." https://en.wikipedia.org/wiki/Recursion What's the signature of that function? Even if you can answer that, there's still the issue of `f(x) {if (c) {return g(f(h(x)), f(i(x));} return d;}`, (for example, Fibonacci), which is not convertible to iteration without allocating a dynamic list of some sort, arguably making it a different algorithm altogether. – Mooing Duck Jul 25 '16 at 05:23
  • @MooingDuck: "`while` loops are a form of recursion" does not mean "any recursive function can be expressed as a `while` loop". – Giorgio Jul 25 '16 at 06:32
  • 1
    @Giorgio Looking at the upvotes of the different answers, it seems pretty clear that most programmers assume the standard definition of "recursion" and not the theoretical CS concept. I'm not sure if you're really confused about this, or just trying to show off. – Voo Jul 25 '16 at 07:24
  • 1
    @Voo: I do not respond to the provocation. I found it interesting to point out the link to TCS but I have also used a standard, non TCS definition of recursion taken from wikipedia. According to this definition a `while` loop is a form of recursion. – Giorgio Jul 25 '16 at 07:36
  • You can convert any piece of code into `fn() { original_code; if (false) fn(); }`. So is everything intrinsically recursion with recursion depth 1? And if everything is intrinsically recursion, the word loses any meaning. – hyde Jul 25 '16 at 08:36
  • @hyde: Since the computation performed by `while p do c` is defined as `if p then (c; while p do c))` and, by definition, "Recursion occurs when a thing is defined in terms of itself.", then, the computation defined by a `while` loop is a form of recursion because it is defined in terms of itself. In your example, `original_code` is not defined in terms of itself, so how is it related to this answer? – Giorgio Jul 25 '16 at 08:53
  • No one would object to the claim that, in theoretical CS, `(while p c)` can be *treated as equivalent to* `(lambda (p c) (if p (do c (recurse p c))))`. But to say that "they are the same thing" is *bad pedagogy* for the same reason that insisting the number 2 "is" the set `{ {}, { {} } }`, in a class that isn't about set-theoretic foundations, is bad pedagogy. – zwol Jul 26 '16 at 15:45
2

A tail call (or tail recursive call) is exactly implemented as a "goto with arguments" (without pushing any additional call frame on the call stack) and in some functional languages (Ocaml notably) is the usual way of looping.

So a while loop (in languages having them) can be seen as ending with a tail call to its body (or its head test).

Likewise, ordinary (non tail-call) recursive calls can be simulated by loops (using some stack).

Read also about continuations and continuation-passing style.

So "recursion" and "iteration" are profoundly equivalent.

Basile Starynkevitch
  • 32,434
  • 6
  • 84
  • 125
1

It is true that both recursion and unbounded while-loops are equivalent in terms of computational expressiveness. That is, any program written recursively can be rewritten into an equivalent program using loops instead, and vice versa. Both approaches are turing-complete, that is either can be used to compute any computable function.

The fundamental difference in terms of programming is that recursion allows you to make use of data that gets stored on the call stack. To illustrate this, assume you want to print a elements of a singly-linked list using either a loop or recursion. I'll use C for the example code:

 typedef struct List List;
 struct List
 {
     List* next;
     int element;
 };

 void print_list_loop(List* l)
 {
     List* it = l;
     while(it != NULL)
     {
          printf("Element: %d\n", it->element);
          it = it->next;
     }
 }

 void print_list_rec(List* l)
 {
      if(l == NULL) return;
      printf("Element: %d\n", l->element);
      print_list_rec(l->next);
 }

Simple, right? Now let's make one slight modification: Print the list in the reverse order.

For the recursive variant, this is an almost trivial modification to the original function:

void print_list_reverse_rec(List* l)
{
    if (l == NULL) return;
    print_list_reverse_rec(l->next);
    printf("Element: %d\n", l->element);
}

For the loop function though, we have a problem. Our list is singly-linked and thus can only be traversed forward. But since we are printing in reverse, we have to start printing the last element. Once we reached the last element, we cannot go back to the second-to-last element anymore.

So we either have to do a whole lot of re-traversing, or we have to build an auxiliary data structure that keeps track of the visited elements and from which we can then print efficiently.

Why don't we have this problem with recursion? Because in recursion we already have an auxiliary data structure in place: The function call stack.

Since recursion allows us to return to the previous invocation of the recursive call, with all local variables and state for that call still intact, we gain some flexibility that would be tedious to model in the iterative case.

ComicSansMS
  • 265
  • 1
  • 5
  • 1
    Of course, the second recursive function is not tail-recursive - it's a lot harder to optimise for space as you can't use TCO to reuse the stack. Implementing a doubly linked list would make both algorithms trivial either way, at the cost of the space of a pointer/reference per element. – Baldrickk Jul 25 '16 at 15:40
  • @Baldrickk The funny thing about tail-recursion is that you end up with a version that is much closer to what the loop version would have looked like, as it again removes your ability to store state on the call stack. A doubly linked list would solve it, but redesigning the data structure is often not an option when running into this problem. While the example here is somewhat artificially constrained, it illustrates a pattern that pops up frequently in functional languages in the context of recursive algebraic types. – ComicSansMS Jul 25 '16 at 20:28
  • My point was that if you run into this problem, it's more down to a lack of functional design, than which language constructs you use to implement it, and each choice has its own positives and negatives :) – Baldrickk Jul 26 '16 at 12:21
0

Loops are a special form of recursion to achieve a specific task (mostly iteration). One can implement a loop in a recursive style with the same performance [1] in several languages. and in the SICP [2], you can see for loops are described as "syntastic sugar". In most imperative programming languages, for and while blocks are using the same scope as their parent function. Nonetheless, in most of the functional programming languages there is neither for nor while loops exist because there is no need for them.

The reason imperative languages have for/while loops is that they are handling states by mutating them. But actually, if you look from different perspective, if you think of a while block as a function itself, taking parameter, process it, and return a new state - which could as well be the call of the same function with different parameters - you can think of loop as a recursion.

The world could also be defined as mutable or immutable. if we define the world as a set of rules, and call an ultimate function that takes all the rules, and the current state as parameters, and return the new state according to these parameters which has the same functionality (generate next state in the same way), we could as well say that is a recursion and a loop.

in the following example, life is the function takes two parameters "rules" and "state", and new state will be constructed in the next time tick.

life rules state = life rules new_state
    where new_state = construct_state_in_time rules state

[1]: tail call optimization is a common optimization in functional programming languages to use the existing function stack in recursive calls instead of creating a new one.

[2]: Structure and Interpretation of Computer Programs, MIT. https://mitpress.mit.edu/books/structure-and-interpretation-computer-programs

  • Any downvoter cares to drop a comment? – Giorgio Jul 25 '16 at 08:15
  • 4
    @Giorgio Not my downvote, but just a guess: I think most programmers feel, that recursion implies there is a recursive function call, because, well, that's what recursion is, a function calling itself. In a loop, there is no recursive function call. So saying that a loop without recursive function call is a special form of recursion would be blatantly wrong, if going by this definition. – hyde Jul 25 '16 at 08:48
  • 2
    Well, maybe looking to it from a more abstract point of view, what seem to be different things, are actually conceptually the same. I find it pretty discouraging and sad to think that people downvote answers just because they do not correspond to their expectations instead of taking them as a chance to learn something. All the answers that try to say: "Hey, look, these things look different on the surface, but are actually the same at a more abstract level" have been downvoted. – Giorgio Jul 25 '16 at 08:58
  • Abstraction, after all, is one of the most powerful tools programmers can use. Being able to view different things under a unified view saves some brain cells that can be used more productively to solve concrete problems instead of dealing with implementation details that are not essential. – Giorgio Jul 25 '16 at 09:00
  • "I think most programmers feel, that recursion implies there is a recursive function call, because, well, that's what recursion is, a function calling itself.": This is a wrong assumption: recursive functions are an example of recursion. I do not see how sticking to this restrictive definition can be useful if you want to better understand the programming patterns you are using all the time. – Giorgio Jul 25 '16 at 09:02
  • 3
    @Georgio: The purpose of this site is to get answers to questions. Answers which are helpful and correct deserve upvotes, answers which are confusing and unhelpful deserve downvotes. An answer which subtly uses a different definition of a common term *without making it clear what different definition is used* is confusing and unhelpful. Answers which only makes sense if you already know the answer, so to speak, are not helpful, and only serves to show the writers superior grasp of terminology. – JacquesB Jul 25 '16 at 09:03
  • 3
    @JacquesB: "Answers which only makes sense if you already know the answer, so to speak, are not helpful...": This can also be said of answers that only confirm what the reader already knows or thinks to know. If an answer introduces terminology that is not clear, it is possible to write comments to ask for more details before downvoting. – Giorgio Jul 25 '16 at 09:11
  • 4
    Loops are *not* a special form of recursion. Look at computability theory and e.g. the theoretical WHILE language and µ-calculus. Yes, some languages use loops as syntactic sugar to *actually* use recursion behind the scenes, but they can do that because recursion and iteration are *equally expressive*, not because they are the same. – Polygnome Jul 25 '16 at 11:03
  • @Polygnome: "Loops are not a special form of recursion." You are right, I am not clear enough. What I meant is the usage of loops in programming languages. Loops are basically repetition of procedures. The reason a language have for/while loops is because they are handling states by mutating them, while in recursion they are handling states by just processing a new state by passing new values. – a25bedc5-3d09-41b8-82fb-ea6c353d75ae Jul 25 '16 at 11:43
  • @Polygnome: "recursion and iteration are equally expressive, not because they are the same." I am not saying that they are the same things, and the definition of expressiveness really differs in real world. Not talking about "computability", "computation power", or "turing completeness". In programming expressiveness is way more than these. – a25bedc5-3d09-41b8-82fb-ea6c353d75ae Jul 25 '16 at 12:54
  • Expressiveness is actually well defined in CS. We are on programmers here, not SO, so we can use the correct, established terms. – Polygnome Jul 25 '16 at 15:16
  • "Loops are a special form of recursion" is wrong. It's actually more that recursion is a special form of iteration. – Dave Cousineau Jul 25 '16 at 19:22
  • @Sahuagin: yes, you're right in terminological view. But what I tried to point out was in programming languages view. when you code, it is more like writing down a procedure that achieves some task according to your initial control value. And repeat calling the same procedure with different control value, so the resulting functionality will be different according to "state" (in that case "while (i < 10)") your state will depend on "i". – a25bedc5-3d09-41b8-82fb-ea6c353d75ae Jul 25 '16 at 20:08
-1

A while loop is different than recursion.

When a function is called, the following takes place:

  1. A stack frame is added to the stack.

  2. The code pointer moves to the beginning of the function.

When a while loop is at the end the following occurs:

  1. A condition asks if something is true.

  2. If so, the code jumps to a point.

In general, the while loop is akin to the following pseudocode:

 if (x)

 {

      Jump_to(y);

 }

Most important of all, recursion and loops have different assembly code representations, and machine code representations. This means that they are not the same. They may have the same results, but the different machine code proves they are not 100% the same thing.

user64742
  • 145
  • 7
  • 2
    You are talking about the implementation of a procedure call and of a while loop and, since they are implemented differently, you conclude that they are different. However, conceptually the are very similar. – Giorgio Jul 25 '16 at 04:49
  • 1
    Depending on compiler, an optimized, inlined recursion call might well produce the same assembly, as plain loop. – hyde Jul 25 '16 at 07:25
  • @hyde ... which is only an example for the well-known fact that one can be expressed through the other; doesn't mean they are identical. A bit like mass and energy. Of course one can argue that all ways to produce identical output are "the same". If the world were finite, all programs would be constexpr, in the end. – Peter - Reinstate Monica Jul 25 '16 at 10:59
  • @Giorgio Nah, it's a logical description, not an implementation. We know that the two things are *equivalent*; but equivalence is not *identity*, because the question (and the answers) is exactly *how* we get to the result, i.e. they necessarily contain algorithmic descriptions (which can be expressed in terms of stack and variable etc.). – Peter - Reinstate Monica Jul 25 '16 at 11:05
  • 1
    @PeterA.Schneider Yeah, but this answer states "Most important of all...different assembly code", which is not quite right. – hyde Jul 25 '16 at 12:30
  • @hyde That is right. For example, an optimizing compiler would be free to compile both a recursive and an iterative faculty function taking integers into a lookup table for the few dozen values which produce valid results, or straight into constants when called with a constant argument. The assembler proof idea is treacherous ;-). – Peter - Reinstate Monica Jul 25 '16 at 13:33
  • @hyde i am going off of the tradittional assembly code for them that I learned. Obviously, people can make things compile differently. The default gcc compiler for c does it that way though. – user64742 Jul 26 '16 at 04:03
-1

Just iteration is insufficient to be generally equivalent to recursion, but iteration with a stack is generally equivalent. Any recursive function can be reprogrammed as an iterative loop with a stack, and vice-versa. This does not mean that it is practical, however, and in any particular situation one or the other form may have clear benefits over the other version.

I'm not sure why this is controversial. Recursion and iteration with a stack are the same computational process. They are the same "phenomenon", so to speak.

The only thing I can think of is that when looking at these as "programming tools", I would agree that you should not think of them as the same thing. They are "mathematically" or "computationally" equivalent (again iteration with a stack, not iteration in general), but that doesn't mean you should approach problems with the thought that either one will do. From an implementation/problem-solving point of view, some problems may work better one way or the other, and your job as a programmer is to decide correctly which one is better suited.

To clarify, the answer to the question Is a while loop intrinsically a recursion? is a definite no, or at least "not unless you have stack as well".

Dave Cousineau
  • 313
  • 3
  • 10