While formulating an answer to another SO question, I came across some strange behaviour regarding tail recursion in Mathematica.
The Mathematica documentation hints
The idea of this answer is to replace the brackets () by a wrapper that does not make our expressions grow. Note that the function we are finding an alternative for is really CompoundExpression, as the OP was correct in remarking this function was ruining the tail recursion (see also the answer by Leonid). Two solutions are provided. This defines the first wrapper
SetAttributes[wrapper, HoldRest];
wrapper[first_, fin_] := fin
wrapper[first_, rest__] := wrapper[rest]
We then have that
Clear[f]
k = 0;
mmm = 1000;
f[n_ /; n < mmm] := wrapper[k += n, f[n + 1]];
f[mmm] := k + mmm
Block[{$IterationLimit = Infinity}, f[0]]
Correctly calculates Total[Range[1000]].
------Note-----
Note that it would be misleading to set
wrapper[fin_] := fin;
As in the case
f[x_]:= wrapper[f[x+1]]
Tail recursion does not occur (because of the fact that wrapper, having HoldRest, will evaluate the singular argument before applying the rule associated with wrapper[fin_]).
Then again, the definition above for f is not useful, as one could simply write
f[x_]:= f[x+1]
And have the desired tail recursion.
------Another note-----
In case we supply the wrapper with a lot arguments, it may be slower than necessary. The user may opt to write
f[x_]:=wrapper[g1;g2;g3;g4;g5;g6;g7 , f[x+1]]
Second wrapper
The second wrapper feeds its arguments to CompoundExpression and will therefore be faster than the first wrapper if many arguments are provided. This defines the second wrapper.
SetAttributes[holdLastWrapper, HoldAll]
holdLastWrapper[fin_] := fin
holdLastWrapper[other_, fin_] :=
Function[Null, #2, HoldRest][other, fin]
holdLastWrapper[others__, fin_] :=
holdLastWrapper[
Evaluate[CompoundExpression[others, Unevaluated[Sequence[]]]], fin]
Note: Returning (empty) Sequences might be very useful in recursion in general. See also my answer here
https://mathematica.stackexchange.com/questions/18949/how-can-i-return-a-sequence
Note that this function will still work if only one argument is provided, as it has attribute HoldAll rather than HoldRest, so that setting
f[x]:= holdLastWrapper[f[x+1]]
Will yield a tail recursion (wrapper does not have this behavior).
Speed comparison
Let's create a nice long list (actually an expression with Head Hold) of instructions
nnnn = 1000;
incrHeld =
Prepend[DeleteCases[Hold @@ ConstantArray[Hold[c++], nnnn],
Hold, {2, Infinity}, Heads -> True], Unevaluated[c = 0]];
For these instructions, we can compare the performance (and outcome) of our wrappers with CompoundExpression
holdLastWrapper @@ incrHeld // Timing
CompoundExpression @@ incrHeld // Timing
wrapper @@ incrHeld // Timing
--> {{0.000856, 999}, {0.000783, 999}, {0.023752, 999}}
Conclusion
The second wrapper is better if you are not exactly sure when tail recursion will happen or how many arguments you will feed to the wrapper. If you are intent on feeding the wrapper 2 arguments, for example in the case where you realize all the second wrapper does is feed to CompoundExpression and you decide to do this yourself, the first wrapper is better.
-----final note----
In CompoundExpression[args, Unevaluated[expr]], expr still gets evaluated before CompoundExpression is stripped, so solutions of this type are no use.