Concepts / Recursion

Recursion

A separate thread is useful for animation when the thread runs a recursive algorithm and the display must be redrawn many times during the recursion.

  • Programming
Interactive lab

Try it: The Call Stack

How the call stack keeps track of function calls: each call pushes a frame with its own arguments and local variables, and each return pops it.

How it works

  1. Calling a function pushes a new frame on top of the stack; the caller pauses.
  2. The frame holds that call's parameters and local variables.
  3. When the function returns, its frame is popped and the return value goes back to the paused caller.
  4. A recursive function pushes one frame per call until the base case, then the frames unwind in reverse order.

Default run (17 steps): Program starts: main is about to call factorial(4). … The stack is empty again. Result: 24. Deepest point: 4 frames, 4 calls in total.

Educational simulation

Loading the simulation…

Watching a Sort Take Shape

Imagine you want to watch a sorting algorithm work instead of only reading its output. A list of colors arrives in a random order, and over several seconds you see the colors move into place one step at a time. Each change on screen corresponds to a real step inside the algorithm. This article is about that situation: an animation that shows a recursive algorithm while it runs.

Keep one question in mind as you read. The algorithm is recursive, so it calls itself repeatedly, and the screen must be refreshed many times during that process. Where should the code that updates the screen live, and what work does the thread have to do to keep the algorithm and the display moving together? The rest of this article works toward answering that question, and then turns to a second kind of recursion that appears when you read grammar rules.

Why a Thread Carries the Recursion

A recursive algorithm solves a problem by having a method call itself on smaller pieces of the problem. The call stack grows and shrinks as the work proceeds, and the order of steps is determined by those nested calls. In the animation case, the program is sorting an array of colors with a recursive QuickSort, and the goal is to arrange the colors into a standard spectrum running from red to violet. The colors begin in a randomized order.

Key point

The central claim is this: a separate thread is useful for animation when the thread runs a recursive algorithm and the display must be redrawn many times during the recursion.

The reason to use a separate thread is that the recursive work gets its own flow of control. The thread can carry the entire recursion from start to finish while the rest of the program keeps responding. Each time the algorithm reaches a point where something visible has changed, the program can update the display. Because the recursion runs in the thread, these redraws happen as part of the sorting process rather than on a separate schedule that must somehow keep up with it.

Userclicks StartSort threadruns recursive QuickSortDisplayshows current colorsstart sort; Start becomes Finishrecursive pass changes arrangementredraw after each visible changeupdated colors on screenFinish aborts sort early if chosen
In what order do the recursion's steps, the redraw calls, and the display updates happen over time?

In words, the diagram says this: once the user starts the sort, the thread takes over and runs a recursive QuickSort. Each pass through the recursion can change the arrangement of colors, and the display is refreshed as those changes happen. The arrow from the thread back to itself stands for the recursion continuing. The diagram is a simplified picture of the control flow and does not show every internal call that QuickSort makes. The Start button becomes a Finish button during the sort, which lets the user abort before the sort finishes on its own.

The Timer Problem

A tempting alternative is to drive the animation with a timer that fires at regular intervals. Each tick would advance the algorithm by one step and then redraw. The difficulty is that a recursive algorithm is not organized as a list of separate, equally sized steps waiting to be taken one at a time. Its natural structure is a single method that keeps calling itself until the job is done.

To see why, consider what a timer tick would have to do. The recursion is in the middle of nested calls, each waiting on the ones inside it. To resume after a tick, the program would need to know exactly where it was in that nested structure and what work remained pending. Forcing the recursion into fixed timer steps means splitting one connected process into many disconnected pieces, and the pieces have to be reassembled correctly each time. A single recursive call inside a thread avoids this, because the recursion keeps its own place in its flow of control while the thread runs.

Reading a BNF Rule

The second half of this article moves from algorithms to grammars. Consider a short question: how would you tell a computer which word sequences count as well-formed English sentences? You cannot list every sentence, because there are infinitely many. Backus-Naur Form, usually called BNF, answers this with a small set of rules. Each rule describes one kind of phrase in terms of other kinds of phrase, and some rules end up describing themselves.

Definition

A BNF rule has the form <symbol> ::= <definition>. The left side names the thing being defined, written in angle brackets. The double-colon-equals sign is read as 'can be', so the rule says the symbol on the left can be the pattern on the right.

The word 'can be' is chosen deliberately. A symbol may have several rules, each giving one possible form, so a rule describes an option rather than a single fixed shape. The next rule shows the idea in a form you can read directly. A noun-phrase can be a common-noun, optionally followed by the literal word 'that' and a verb-phrase. Alternatively, it can be a common-noun followed by zero or more prepositional-phrases.

<noun-phrase>symbol being defined::=read as 'can be'<common-noun>first part of the pattern,defined by its own rulethatliteral word, appears aswritten<verb-phrase>refers to another rule
Which part of the rule is the symbol being defined, and which part lists the strings it permits?

The rule can also be read as a recipe. To produce a noun-phrase by this alternative, produce a common-noun, then the literal word 'that', then produce a verb-phrase after it. The rule does not say how to produce a common-noun or a verb-phrase. Those symbols must be defined by other BNF rules, so a grammar is a collection of rules that refer to one another until every symbol has a definition.

Recursive Rules and Loops

A rule is recursive when it defines a symbol partly in terms of the same symbol, either directly or through other rules. Rules like the noun-phrase rule can describe quite complicated structures, but the more important feature is that a rule may refer back to a symbol it helped define. Recursion lets a small grammar describe phrases of unlimited depth. The two forms of recursion differ in how many rules the loop passes through.

Tracing a Nested Phrase

Recursion becomes concrete when you build a phrase step by step. Start with a noun-phrase that is a common-noun followed by 'that' and a verb-phrase. The verb-phrase can be 'ate the cheese', which gives the noun-phrase 'the rat that ate the cheese'. Now the loop can be used again. Put that whole noun-phrase inside a verb-phrase, and place that verb-phrase after a common-noun. The result is a larger noun-phrase.

Worked example

Building 'the cat that caught the rat that ate the cheese'

Show which rule application produces each part of the phrase 'the cat that caught the rat that ate the cheese'.

  1. 1
    Inner phrase

    Use the first alternative of the noun-phrase rule: common-noun 'rat', then 'that', then verb-phrase 'ate the cheese'. This yields 'the rat that ate the cheese'.

  2. 2
    Verb-phrase around it

    Build a verb-phrase as a verb followed by a noun-phrase: verb 'caught', then the noun-phrase from the previous step. This yields 'caught the rat that ate the cheese'.

  3. 3
    Outer phrase

    Use the noun-phrase rule again: common-noun 'cat', then 'that', then the verb-phrase from the previous step. This yields 'the cat that caught the rat that ate the cheese'.

  4. 4
    Loop check

    The noun-phrase rule led to the verb-phrase rule, which led back to a noun-phrase. The loop between the two rules is what produced the second layer of nesting.

Result

The full phrase is derived by applying the noun-phrase and verb-phrase rules in a loop, each application wrapping the previous result.

What do you think happens?

Does 'rat that ate the cheese' match the first alternative of the noun-phrase rule, common-noun followed by 'that' and a verb-phrase?

  • Yes

  • No

Reveal answer
Answer:

Yes

'rat' is the common-noun, 'that' is the literal word, and 'ate the cheese' is a verb-phrase, which the source gives as one valid choice for the verb-phrase rule.

Tracing works in the other direction too. To debug a failing derivation, trace from the outside in and identify the first rule where the expected word does not match. Consider the generated phrase 'the cat that caught the rat which ate the cheese'. The outer noun-phrase matches 'the cat that', and the verb-phrase begins with 'caught'. The verb-phrase then needs a noun-phrase, which begins with the common-noun 'rat'. The rule expects the literal 'that' next, but the input has 'which'. The first mismatch is therefore inside the inner noun-phrase rule, at the literal 'that'.

noun-phraseouter, matches 'the catthat'common-noun: the catmatchedverb: caughtmatchedcommon-noun: the ratmatchedthatmatchednoun-phraseinner rule, where matchingfailsthat (expected)found: whichverb-phrasematched so farfirst partliteralverb-phraseverbnoun-phrasecommon-nounliteral
Which rule application produced each part of the nested phrase, and at which rule does the derivation stop matching the input?

The tree shows the failure clearly. The derivation matched every part it could, from the outside in, and stopped at the literal 'that' inside the noun-phrase rule for 'rat'. That is the rule where the derivation fails to match the input. The fix is not to change the outer rules, which matched correctly, but to recognize that the phrase uses a different word than the grammar allows at that point.

Mistakes Readers Make with Recursive Rules

  • Common mistake

    Reading a rule as a single fixed shape

    What it looks like

    Treating <noun-phrase> ::= <common-noun> that <verb-phrase> as the only form a noun-phrase can take.

    Why it fails

    The symbol may have several rules, and the 'can be' reading means each rule gives one option.

    Do this instead

    Read every rule for the same symbol, then decide which alternative fits the phrase you are checking.

  • Common mistake

    Expecting a recursive rule to refer to itself on the same line

    What it looks like

    Looking only at the noun-phrase rule and concluding it is not recursive because it never names noun-phrase.

    Why it fails

    Indirect recursion crosses between rules, so the loop only shows up when the rules are read together.

    Do this instead

    Follow each mentioned symbol to its own rule and check whether the chain returns to where it started.

  • Common mistake

    Treating a derivation failure as a problem with the whole grammar

    What it looks like

    Rewriting every rule after the phrase 'the cat that caught the rat which ate the cheese' fails.

    Why it fails

    The outer rules may match correctly, and only one literal may be wrong.

    Do this instead

    Trace from the outside in and stop at the first rule where the expected word does not match the input.

  • Common mistake

    Assuming the timer version of the animation is equally simple to write as a single recursive call

Practice Tracing a Derivation

MEDIUM

Using the noun-phrase rule and the verb-phrase rule from this article, derive the phrase 'the mouse that chased the cat that caught the rat'. For each step, name the rule application that produced the words. Then state whether the loop between noun-phrase and verb-phrase is passed through once or twice.

Hints
  • Start from the innermost phrase, which is 'the rat' inside a verb-phrase that you can build from 'caught'.
  • Count how many times control moves from a noun-phrase into a verb-phrase and back.
  • If a word does not match a rule, stop at that rule and report it, as in the failing example above.

Key Takeaways

  • A recursive algorithm is a good fit for a separate thread because the thread can carry the whole recursion while the display is redrawn many times during it.
  • Splitting a recursive algorithm into a series of timer-driven method calls is awkward because its natural structure is one method that keeps calling itself.
  • A BNF rule has the form <symbol> ::= <definition>, read as 'can be', and a symbol may have several rules, each giving one possible form.
  • A rule is recursive when it refers to its own symbol, either directly within one rule or indirectly through a loop across several rules.
  • To debug a failing derivation, trace from the outside in and identify the first rule where the expected word does not match the input.