(* Tail recursion ..... *) (* consider the following function *) fun f n = if n = 0 then 1 else n * f(n-1); (* A call to f 4 will proceed as follows: f 4 => 4 * f(4-3) => 4 * f(3) => 4 * (3 * f(3-1)) => 4 * (3 * f(2)) => 4 * (3 * (2 * f(2-1))) => 4 * (3 * (2 * f(1))) => 4 * (3 * (2 * (1 * f(1-1)))) => 4 * (3 * (2 * (1 * f(0)))) => 4 * (3 * (2 * (1 * 1))) => 4 * (3 * (2 * 1)) => 4 * (3 * 2) => 4 * 6 => 24 Therefore, as the recursion proceeds more and more numbers are waiting to be multiplied, and the multiplication cannot be performed until recursion terminates with the call to f 0. Therefore, we might think/say that f is wasting space. *) (* consider the following function *) fun f1 (n,p) = if n = 0 then p else f1(n-1,n*p); (* A call to f1 (4,1) proceeds as follows: f1(4,1) => f1(4-1,4*1) => f1(3,4) => f1(3-1,3*4) => f1(2,12) => f1(2-1,2*12) => f1(1,24) => f1(1-1,1*24) => f1(0,24) => 24 In f1 the intermediate expressions stay small. The multiplications are not delayed, not stacked up, but are performed at once. Storage requirements remain constant for all values of n. The evaluation is "iterative", also known as (aka) "tail recursive", aka "terminal recursive". Many recursive functions can be made iterative by adopting the above approach. *)