Actually you should break the function down first:

A loop has a few parts:

  1. the header, and processing before the loop. May declare some new variables

  2. the condition, when to stop the loop.

  3. the actual loop body. It changes some of the header's variables and/or the parameters passed in.

  4. the tail; what happens after the loop and return result.

Or to write it out:

foo_iterative(params){
    header
    while(condition){
        loop_body
    }
    return tail
}

Using these blocks to make a recursive call is pretty straightforward:

foo_recursive(params){
    header
    return foo_recursion(params, header_vars)
}

foo_recursion(params, header_vars){
    if(!condition){
        return tail
    }

    loop_body
    return foo_recursion(params, modified_header_vars)
}

Et voilà; a tail recursive version of any loop. breaks and continues in the loop body will still have to be replaced with return tail and return foo_recursion(params, modified_header_vars) as needed but that is simple enough.


Going the other way is more complicated; in part because there can be multiple recursive calls. This means that each time we pop a stack frame there can be multiple places where we need to continue. Also there may be variables that we need to save across the recursive call and the original parameters of the call.

We can use a switch to work around that:

bar_recurse(params){
    if(baseCase){
        finalize
        return
    }
    body1
    bar_recurse(mod_params)
    body2
    bar_recurse(mod_params)
    body3
}


bar_iterative(params){
    stack.push({init, params})

    while(!stack.empty){
        stackFrame = stack.pop()

        switch(stackFrame.resumPoint){
        case init:
            if(baseCase){
                finalize
                break;
            }
            body1
            stack.push({resum1, params, variables})
            stack.push({init, modified_params})
            break;
        case resum1:
            body2
            stack.push({resum2, params, variables})
            stack.push({init, modified_params})
            break;
        case resum2:
            body3
            break;
        }
    }
}
Answer from ratchet freak on Stack Exchange
🌐
Refactoring
refactoring.com › catalog › replaceIterationWithRecursion.html
Replace Iteration with Recursion - Refactoring
(it is, of course, possible to ... version) Identify the candidate loop. The loop should modify one or more scoped locals, and then return a result based on their final values. Move the loop into a new function. Compile and rerun tests. Replace the loop with a function that accepts the local variables, and which returns the final result...
Top answer
1 of 2
49

Actually you should break the function down first:

A loop has a few parts:

  1. the header, and processing before the loop. May declare some new variables

  2. the condition, when to stop the loop.

  3. the actual loop body. It changes some of the header's variables and/or the parameters passed in.

  4. the tail; what happens after the loop and return result.

Or to write it out:

foo_iterative(params){
    header
    while(condition){
        loop_body
    }
    return tail
}

Using these blocks to make a recursive call is pretty straightforward:

foo_recursive(params){
    header
    return foo_recursion(params, header_vars)
}

foo_recursion(params, header_vars){
    if(!condition){
        return tail
    }

    loop_body
    return foo_recursion(params, modified_header_vars)
}

Et voilà; a tail recursive version of any loop. breaks and continues in the loop body will still have to be replaced with return tail and return foo_recursion(params, modified_header_vars) as needed but that is simple enough.


Going the other way is more complicated; in part because there can be multiple recursive calls. This means that each time we pop a stack frame there can be multiple places where we need to continue. Also there may be variables that we need to save across the recursive call and the original parameters of the call.

We can use a switch to work around that:

bar_recurse(params){
    if(baseCase){
        finalize
        return
    }
    body1
    bar_recurse(mod_params)
    body2
    bar_recurse(mod_params)
    body3
}


bar_iterative(params){
    stack.push({init, params})

    while(!stack.empty){
        stackFrame = stack.pop()

        switch(stackFrame.resumPoint){
        case init:
            if(baseCase){
                finalize
                break;
            }
            body1
            stack.push({resum1, params, variables})
            stack.push({init, modified_params})
            break;
        case resum1:
            body2
            stack.push({resum2, params, variables})
            stack.push({init, modified_params})
            break;
        case resum2:
            body3
            break;
        }
    }
}
2 of 2
2

Following up on @ratchet freak's answer, I created this example of how the Fibonacci function can be rewritten to a while loop in Java. Note that There's a much simpler (and efficient) way to rewrite the Fibonacci with a while loop though.

class CallContext { //this class is similar to the stack frame

    Object[] args;

    List<Object> vars = new LinkedList<>();

    int resumePoint = 0;

    public CallContext(Object[] args) {
        this.args = args;
    }

}


static int fibonacci(int fibNumber) {
    Deque<CallContext> callStack = new LinkedList<>();
    callStack.add(new CallContext(new Object[]{fibNumber}));
    Object lastReturn = null; //value of last object returned (when stack frame was dropped)
    while (!callStack.isEmpty()) {
        CallContext callContext = callStack.peekLast();
        Object[] args = callContext.args;
        //actual logic starts here
        int arg = (int) args[0];
        if (arg == 0 || arg == 1) {
            lastReturn = arg;
            callStack.removeLast();
        } else {
            switch (callContext.resumePoint) {
                case 0: //calculate fib(n-1)
                    callStack.add(new CallContext(new Object[]{arg - 1}));
                    callContext.resumePoint++;
                    break;
                case 1: //calculate fib(n-2)
                    callContext.vars.add(lastReturn); //fib1
                    callStack.add(new CallContext(new Object[]{arg - 2}));
                    callContext.resumePoint++;
                    break;
                case 2: // fib(n-1) + fib(n-2)
                    callContext.vars.add(lastReturn); //fib2
                    lastReturn = (int) callContext.vars.get(0) + (int) callContext.vars.get(1);
                    callStack.removeLast();
                    break;
            }
        }
    }
    return (int) lastReturn;
}
Discussions

c - How to Replace For Loops with Recursion - Stack Overflow
I'm just getting started with recursive programming -- and since I've heard how powerful this is for problem-solving, I would like to give it a try on a simple decryption algorithm I wrote a few da... More on stackoverflow.com
🌐 stackoverflow.com
September 29, 2018
freeCodeCamp Challenge Guide: Replace Loops using Recursion - Guide - The freeCodeCamp Forum
Replace Loops using Recursion Hints Hint 1: When n More on forum.freecodecamp.org
🌐 forum.freecodecamp.org
130
February 22, 2020
Replace loop using recursion
Tell us what’s happening: I think the code is buggy, since i am using recursion and it is still asking me to use recursoin in order to get the lesson. by the way thanks to the creators of this site for including extra lessons. Your code so far js function sum(arr, n) { // Only change code ... More on forum.freecodecamp.org
🌐 forum.freecodecamp.org
1
1
October 18, 2019
replace for loop with recursive function for
i am working on simple js function... can u tell me how to replace the loop with recursive function.. providing my code below in the fiddle.. I am trying to learn js http://jsfiddle.net/utbsgnzu... More on stackoverflow.com
🌐 stackoverflow.com
May 25, 2017
Top answer
1 of 4
6

If you can accomplish a task without recursion its a good idea to solve it that way. If you would like to learn about recursion check out some problems like factorial or Fibonacci. These also have iterative solutions but lend themselves much more to recursion than the problem you have here. In this case it is very clear what your algorithm is doing and recursion would make it needlessly harder to understand. Here is one improvement you could make however

for (int e = 0; e < length; e++)
{
    key[4] = letters[e];
    for (int d = 0; d < length; d++)
    {
        key[3] = letters[d];
        for (int c = 0; c < length; c++)
        {
            key[2] = letters[c];
            for (int b = 0; b < length; b++)
            {
                key[1] = letters[b];
                for (int a = 1; a < length; a++)
                {
                    key[0] = letters[a];

                    if (strcmp(crypt(key, salt), hash) == 0)
                    {
                        printf("%s\n", key);
                        return 0;
                    }
                }
            }
        }
    }
} 
2 of 4
2

Although I don't disagree with everyone who has discouraged you from using recursion in this example, I wanted to write it recursively since I think it's a reasonable question.

Here's my attempt at writing it recursively. By doing this, I only need to write the loop once, since the outer loop is handled by the recursion. I've taken some liberties so it isn't exactly equivalent to your code, but I think in principle it is the same (testing all the combinations against hash) and shows the basic idea of how you could write this recursively. I'll assume you have a way of knowing the strcmp check is safe.

int recur(int cur, int klength, char *key, char *letters, int length, char *salt, char *hash)
{
    if (cur == klength)
    {
        if (strcmp(crypt(key, salt), hash))
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
    else
    {
        for (int i = 0; i < length; i++)
        {
            key[cur] = letters[i];
            int j = recur(cur+1, klength, key, letters, length, salt, hash);
            if (!j)
            {
                return 0;
            }
        }
        return 1;
    }
}

I would then call this with

recur(5, 0, ...)

to do the 5 loops you wrote. This isn't very elegant, but I think it's clear why this might be more elegant if you expanded your key to require 10 loops (and why it would be terrible for the stack at 10000 loops).

Having said that, my first thought looking at your code wasn't "recursion" it was "those outer loops look pretty similar, so I'd like to get rid of some of them." My code below isn't pretty (hey, it's late at night!), but I think in principle this would be a better approach if you think you might need to increase the number of characters you're testing to 10 (or 10000). What I'm trying to do is maintain an integer equivalent to key in idx. If I increment idx[0] and it is == length I know I need to reset idx[0] = 0 and try incrementing idx[1], etc. Every time I change idx[i] I make an equivalent change to key[i]. Every time I have a new permutation of idx/key, I do your strcmp test to see if I've found the correct one.

int ksize = 5;
int idx[ksize];
for (int i = 0; i < ksize; ++i)
{
    idx[i] = 0;
    key[i] = letters[0];
}
for (int done = 0; !done; )
{
    if (strcmp(crypt(key, salt), hash) == 0)
    {
        printf("%s\n", key);
        return 0;
    }
    for (int i = 0; ; i++)
    {
        if (++idx[i] == length)
        {
            idx[i] = 0;
        }
        key[i] = letters[idx[i]];
        if (idx[i]) // We incremented idx[i] and it wasn't reset to 0, so this is a new combination to try
        {
            break;
        }
        else if (i == ksize-1) // We incremented idx[ksize-1] and it was reset to 0, so we've tried all possibilities without returning
        {
            done++;
            break;
        }
    }
}
🌐
YouTube
youtube.com › watch
Replace Loops using Recursion - Free Code Camp - YouTube
This is a basic JavaScript tutorial where we replace loops using recursion. Recursion is quite difficult for me to get my head around in general.
Published   November 2, 2019
🌐
Connorocampo
connorocampo.dev › blog › replace-loops-using-recursion
Replace Loops using Recursion (Line-by-line Solution Explanation) | Connor Ocampo's Website
June 3, 2020 - This is a line-by-line code explanation of freeCodeCamp’s Replace Loops using Recursion module in their Basic JavaScript section. As of today, Wednesday June 3rd, 2020, this is what the code challenge looks like:
🌐
YouTube
youtube.com › reboot
Replace Loops using Recursion - Free Code Camp Help - Basic Javascript -Algorithms & Data Structures - YouTube
Free Code Camp Material - To help you learn and walk-through step-by-step.JavaScript Algorithms and Data Structures SectionBasic Javascript Sub-Section Repla...
Published   September 9, 2022
Views   8K
Find elsewhere
🌐
freeCodeCamp
forum.freecodecamp.org › guide
freeCodeCamp Challenge Guide: Replace Loops using Recursion - Guide - The freeCodeCamp Forum
February 22, 2020 - Replace Loops using Recursion Hints Hint 1: When n <= 0 sum(arr, n) returns 0. Hint 2: When n is larger than 0 sum(arr, n) returns sum(arr, n - 1) + arr[n - 1] Solutions: (Click to reveal) function sum(arr, n) { if(…
🌐
GitHub
gist.github.com › sanikamal › 488f895ab6be5b9692a893ef12cf57c9
Basic JavaScript: Replace Loops using Recursion · GitHub
Basic JavaScript: Replace Loops using Recursion. GitHub Gist: instantly share code, notes, and snippets.
🌐
GitHub
github.com › Manish-Giri › FreeCodeCamp › blob › master › curriculum › challenges › english › 02-javascript-algorithms-and-data-structures › basic-javascript › replace-loops-using-recursion.english.md
FreeCodeCamp/curriculum/challenges/english/02-javascript-algorithms-and-data-structures/basic-javascript/replace-loops-using-recursion.english.md at master · Manish-Giri/FreeCodeCamp
However, notice that multiply(arr, n) == multiply(arr, n - 1) * arr[n - 1]. That means you can rewrite multiply in terms of itself and never need to use a loop. function multiply(arr, n) { if (n <= 0) { return 1; } else { return multiply(arr, n - 1) * arr[n - 1]; } } The recursive version of multiply breaks down like this. In the base case, where n <= 0, it returns 1. For larger values of n, it calls itself, but with n - 1.
Author   Manish-Giri
🌐
Hashnode
hashnode.com › post › fcc-basic-javascript-replace-loops-using-recursion-ck9uevoq1046v7bs1gsbmop2t
fCC - Basic JavaScript: Replace Loops using Recursion - Hashnode
May 5, 2020 - However, notice that multiply(arr, n) == multiply(arr, n - 1) * arr[n - 1]. That means you can rewrite multiply in terms of itself and never need to use a loop. function multiply(arr, n) { if (n <= 0) { return 1; } else { return multiply(arr, n - 1) * arr[n - 1]; } } The recursive version of multiply breaks down like this. In the base case, where n <= 0, it returns 1. For larger values of n, it calls itself, but with n - 1.
🌐
freeCodeCamp
forum.freecodecamp.org › javascript
Replace Loops Using Recursion Clarification - JavaScript
February 7, 2020 - Tell us what’s happening: I understand how basic function recursion works, the function is simply re-called within the function I understand that the function is calling itself and only when n <= 0 is false, then e…
🌐
Refactoring
refactoring.com › catalog › replaceRecursionWithIteration.html
Replace Recursion with Iteration - Refactoring
Every Recursion must have a defined base case. In addition, each recursive call must make a progress towards the base case (otherwise recursive calls would be performed infinitely). In our example the base case is n == 0. Implement a loop that will iterate until the base case is reached.
🌐
freeCodeCamp
forum.freecodecamp.org › javascript
Explanation for the given example for Replace Loops with Recursion
July 4, 2022 - Tell us what’s happening: Describe your issue in detail here. Unfortunately, my issue is with the lesson itself, and how it’s very unclear and inadequate, especially for a concept that is a bit mind-boggling to come across for the first time (A function that calls itself???). First line: “Recursion is the concept that a function can be expressed in terms of itself.” This very first line is already a bit iffy.
🌐
Old Dominion University
cs.odu.edu › ~zeil › cs361 › latest › Public › recursionConversion › index.html
Converting Recursion to Iteration
3 weeks ago - Inside this loop, we have the blocks of code from the original recursive routine, but the recursive calls at the end of each block is replaced by a push of the information that we want restored upon “return” from a simulated recursive call and another push that sets up a simulated recursive ...
Top answer
1 of 5
57

It's possible to replace recursion by iteration plus unbounded memory.

If you only have iteration (say, while loops) and a finite amount of memory, then all you have is a finite automaton. With a finite amount of memory, the computation has a finite number of possible steps, so it's possible to simulate them all with a finite automaton.

Having unbounded memory changes the deal. This unbounded memory can take many forms which turn out to have equivalent expressive power. For example, a Turing machine keeps it simple: there's a single tape, and the computer can only move forward or backward on the tape by one step at a time — but that's enough to do anything that you can do with recursive functions.

A Turing machine can be seen as an idealized model of a computer (finite state machine) with some extra storage that grows on demand. Note that it's crucial that not only there isn't a finite bound on the tape, but even given the input, you can't reliably predict how much tape will be needed. If you could predict (i.e. compute) how much tape is needed from the input, then you could decide whether the computation would halt by calculating the maximum tape size and then treating the whole system, including the now finite tape, as a finite state machine.

Another way to simulate a Turing machine with computers is as follows. Simulate the Turing machine with a computer program that stores the beginning of the tape in memory. If the computation reaches the end of the part of the tape that fits in memory, replace the computer by a bigger computer and run the computation again.

Now suppose that you want to simulate a recursive computation with a computer. The techniques for executing recursive functions are well-known: each function call has a piece of memory, called a stack frame. Crucially, recursive functions can propagate information through multiple calls by passing variables around. In terms of implementation on a computer, that means that a function call might access the stack frame of a (grand-)*parent call.

A computer is a processor — a finite state machine (with a huge number of states, but we're doing computation theory here, so all that matters is that it's finite) — coupled with a finite memory. The microprocessor runs one giant while loop: “while the power is on, read an instruction from memory and execute it”. (Real processors are much more complex than that, but it doesn't affect what they can compute, only how fast and conveniently they do it.) A computer can execute recursive functions with just this while loop to provide iteration, plus the mechanism to access memory, including the ability to increase the size of the memory at will.

If you restrict the recursion to primitive recursion, then you can restrict iteration to bounded iteration. That is, instead of using while loops with an unpredictable running time, you can use for loops where the number of iterations is known at the beginning of the loop¹. The number of iterations might not be known at the beginning of the program: it can itself have been computed by previous loops.

I'm not going to even sketch a proof here, but there is an intuitive relationship between going from primitive recursion to full recursion, and going from for loops to while loops: in both cases, it involves not knowing in advance when you'll stop. With full recursion, this is done with the minimization operator, where you keep going until you find a parameter that satisfies the condition. With while loops, this is done by keeping going until the loop condition is satisfied.

¹ for loops in C-like languages can perform unbounded iteration just like while, it's just a matter of convention to restrict them to bounded iteration. When people talk about “for loops” in theory of computation, that means only loops that count from 1 to $n$ (or equivalent).

2 of 5
35

Every recursion can be converted to iteration, as witnessed by your CPU, which executes arbitrary programs using a fetch-execute infinite iteration. This is a form of the Böhm-Jacopini theorem. Moreover, many Turing-complete models of computation have no recursion, for example Turing machines and counter machines.

Primitive recursive functions correspond to programs using bounded iteration, that is, you have to specify the number of iterations that a loop is executed in advance. Bounded iteration cannot simulate recursion in general, since the Ackermann function isn't primitive recursive. But unbounded iteration can simulate any partially computable function.

🌐
GitHub
gist.github.com › shakeelkoper › 40e2b486b80ea7f3774bcb8b65f1c6ad
Replace Loops using Recursion · GitHub
Replace Loops using Recursion. GitHub Gist: instantly share code, notes, and snippets.