Post

Tail Call Optimization

One of the characteristic features of functional programming is recursion concept. Recursions are not suppose to be harder than using loops. Actually often much easier than loop:

  • When processing a tree
  • Avoids mutation, even for local variables

Nevertheless sometimes recurions might be less efficient rather than loops. Then how to reason about efficiency of recursion ?


Call-stacks


In computer science, a call stack is a stack data structure that stores information about the active subroutines of a computer program. A call stack is used for several related purposes, but the main reason for having one is to keep track of the point to which each active subroutine should return control when it finishes executing. Such activations of subroutines may be nested to any level (recursive as a special case), hence the stack structure.

While a program runs, there is a call stack of function calls that have started but not yet returned

  • Calling a function f pushes an instance of f on the stack
  • When a call to f finishes, it is popped from the stack


Tail-call optimization


Tail-call optimization is where you are able to avoid allocating a new stack frame for a function because the calling function will simply return the value that it gets from the called function. We can use the constant stack space when we take advantage of tail-call optimization for the recursive function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
(* Factorial function with recursive call*)
fun fact n = if n=0 then 1 else n*fact(n-1)

val x = fact 3

(*
Evaluation steps

fact 3
3 * (fact 2)
3 * (2 * (fact 1))
3 * (2 * (1 * fact 0))                       
3 * (2 * (1 * 1))
3 * (2 * 1)
3 * 2
6

*)

(* Factorial function with tail recursion *)

fun fact n = 
	let
	   fun aux (n,acc)
			if n = 0
			then acc
			else aux(n-1,acc*n)
	in
	   aux(n,1)
	end

val x = fact 3

(*
Evaluation steps

fact 3
aux (3,1)
aux (2,3)
aux (1,6)
aux (0,6)
6

*)

This post is licensed under CC BY 4.0 by the author.