In your first problem snippet:
exp := u[i - 1, n] + u[i, n - 1];
u[i_, n_] := exp;
The way I think Mathematica does the evaluation of the body of u when you give the parameters 2 2, more or less, is like this:
Clear["Global`*"];
exp := u[i - 1, n] + u[i, n - 1];
(* a more-or-less accurate model of function evaluation *)
Hold[exp] /. {i -> 2, n -> 2} // ReleaseHold
(* u[-1 + i, n] + u[i, -1 + n] *)
So what's happening is that there is no literal i or n symbol in the literal expression of the function. There is no i or n in exp. So by the time the Hold is released, the symbol replacement has already occurred and done nothing, and you end up with a recursive chain of no replacements. One way to force evaluation even within Hold is with Evaluate:
Clear["Global`*"];
exp := u[i - 1, n] + u[i, n - 1];
Hold[Evaluate[exp]] /. {i -> 2, n -> 2} // ReleaseHold
(* u[1, 2] + u[2, 1] *)
Translating this back into the function definition:
...
u[i_, n_] := Evaluate[exp];
...
Which works as expected.
In your second problem snippet:
exp := u[i - 1, n] + u[i, n - 1]
u[i1_, n1_] := (i = i1; n = n1; exp)
We use the same "model" as before:
Clear["Global`*"];
exp := u[i - 1, n] + u[i, n - 1];
Hold[(i = i1; n = n1; exp)] /. {i1 -> 2, n1 -> 2} (* // ReleaseHold *)
(* Hold[i = 2; n = 2; exp] *)
Where you can see that you're assigning into the global symbols of i and n. Maybe that's your intention, and if you ReleaseHold this single application evaluates to the expected expression, but I imagine it would give weird answers because of the multiple branches (after the left branch reaches bottom, those bottom-most i and n are used at the top of the right branch, I think... or something like that. brainhurt).
Mr. Wizard's Block[{i = i1, n = n1}, exp] approach is one way to accomplish the goal here. Throwing it into our evaluation model:
Clear["Global`*"];
exp := u[i - 1, n] + u[i, n - 1];
Hold[Block[{i = i1, n = n1}, exp]] /. {i1 -> 2, n1 -> 2} // ReleaseHold
(* u[1, 2] + u[2, 1] *)
Which evaluates to the correct value but also works in the general case because Block keeps the scope of those i and n within its subexpressions.
A general note: Trace can come in very handy in things like this. It will show you for example whether the i and n are being replaced or not.
Blockworks for my sample, it's not effective for the complicated original one. – xzczd Oct 03 '12 at 08:33RuleDelayedis also unable to climb over the obstacle of intermediate variable. Something likeexp := u[i - 1, n] + u[i, n - 1]; recursion1 = {u[i_, 0] :> i, u[0, n_] :> n, u[i_, n_] :> exp}; u[2, 2] //. recursion1doesn't work. – xzczd Oct 03 '12 at 09:53