Is Recursion hard?
Peter Deutsch, the creator of the smalltalk implementation that inspired the Java-jit (and much else), famously said:
To iterate is human, to recurse divine
So you and your struggling students are in august company!
Now let's turn over to math. And not just math but...
Basic school math
Here are two identities
$$
\begin{aligned}
a(b+c) &= ab + ac & \text{distributive law} \\
x^{m+n} &= x^m x^n & \text{index law}
\end{aligned}
$$
I guess everyone will agree that in the context of school math these are
unproblematic? Almost trivial?
Lets special-case the above with $c=1$ in the first and $n=1$ in the second and we get
$$
\begin{aligned}
a(b+1) &= ab + a \\
x^{m+1} &= xx^m
\end{aligned}
$$
Lets now ponder...
- Are these equations in any way difficult?
- Do you (anyone) find it an issue that they are recursive?
- Does one even notice that they are recursive?
(Assuming that the answer to all the above is no,no,no)
Lets ask now:
Whats this to do with programming?
Well... All we need are base cases, respectively
$$a.0 = 0$$
$$x^0 = 1$$
And we get a complete recursive specification for multiplication as repeated addition and exponentiation as repeated multiplication
These can be trivially1 translated to haskell as
a*(b+1) = a*b + a
a*0 = 0
and
x^(m+1) = x*(x^m)
x^0 = 1
Returning to the Programming world
Ok so you say that this is some math-toy. What's it to do with programming?
An inappropriate pun
In almost all today's programming languages you can write the "statement"
i = 1
And in math we write $i = 1$
Doing the first makes the second true; or staying in the programming world, after i = 1
i == 1
becomes true
So what's the big deal?
Well programmers also write
i = i+1
(Or moral equivalents like i++
i += 1
etc)
So after i = i+1
does i == i+1
?!
Lets ask our math-respecting executor Haskell:
One can easily enough write
i = i+1
And no trouble...it seems
But when we ask what is x
we get, almost literally, an explosion!
? i
ERROR: Control stack overflow
In effect our executor is saying that it got into trouble trying to "solve the equation" $i=i+1$
So is the problem in programming or math??
Mathematicians would almost universally protest at $i=i+1$ as
- wrong
- impossible
- no (finite) solution
- or just plain nonsense
- etc
Clearly if we programmers accept i=i+1
as normal and ok we cannot then expect our programs to respect mathematical concepts.
So it seems we have
An inevitable dilemma: Programming XOR Mathematics
This seems like a very high price to pay!
But there's good news!
A large number of very intelligent people for many decades have thought about the problem and come to a very simple conclusion:
The culprit is assignment
- Once you have assignment, a mathematical semantics of our programming language is a lost cause
- Throw the assignment out of the programming language (and morally equivalent things like mutating data-structures)2 and your programming language essentially becomes mathematics
A bit of terminology
- Those who think as above and prefer assignment-free3 languages are typically called functional4 programmers
- Languages with assignment are called imperative languages (and from the pov above OO and classic imperative languages are much the same)
Conclusion
So in answer to your explicit statement: My students find recursion hard! and its implied questions: Am I or my students doing something wrong?
The answer is Yes: Using imperative programming in a first programming course
5 befuddles their thinking
Or hear Dijkstra's take on this
1 Ok for those who try this in haskell there are some wrinkles -- Ive tested in gofer
-- GOod For Equational Reasoning -- a Haskell predecessor which facilitates this kind of playing around better than Haskell
2 Mutation is actually much worse than assignment; in fact mutation messes up imperative programming as much as imperative programming messes up mathematics. A brief trailer
3 And sequencing... A story for another day
4 "Functional" is actually a misnomer; something like "mathematical" would have been better.
5 Imperative programming of course must be taught; if it is done in a later course, there is no unnecessary confusion.