Call stack #
During the execution of a program, the call stack keeps track of ongoing function/method calls:
when a function/method is called, a frame is pushed on top of the stack: the frame stores information about the execution of the function/method (current value of variables, …),
when the execution of the call terminates, the frame is popped from the stack, and control is passed back to the calling function/method (whose frame is now on top of the stack).
Hint. A debugger provides a representation of the successive states of a call stack, with references to the source code. This gives the illusion of source code being interpreted verbatim.
In Haskell #
Warning. We assume here a simplified call stack, for a naive execution.
The Haskell compiler may produce a program that applies a lazy evaluation strategy, which can be more complex. We will not cover this in detail.
Example. Consider the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13main :: IO () main = print $ function1 5 + function3 3 function1 :: Int -> Int function1 x = 2 * function2 x function2 :: Int -> Int function2 x = x - 1 function3 :: Int -> Int function3 x = 4 * xWhen the function
mainis called, it is added (a.k.a. pushed) to the (previously empty) call stack. This can be represented as:mainWhen execution “reaches” Line 3,
function1is called (with argument5) and added to the stack:function1 5 main : 3 # 3 is a line number hereThen Line 7,
function1callsfunction2(with the argument5still):function2 5 function1 5 : 7 main : 3When the call
function2 5terminates, it returns the value4and passes control back to the previous call in the stack (namelyfunction1 5), which can resume its execution:function1 5 main : 3When this call terminates, it returns the value
8and passes control back to the functionmain, which resumes its execution where it left off:mainWhen execution “reaches” Line 4,
function3is called (with argument3) and added to the stack:function3 3 main : 4After the call
function3 3terminates, it returns the value12, and passes control back to the functionmain, which can now sum the two values that it received (8and12), and print the result.
Recursion and stack overflow #
Note. If a function/method is recursive (i.e. if it calls itself, directly or indirectly), then it may appear multiple times in the call stack. E.g.:
method1 method2 : 16 method1 : 8 <rest of the call stack>
Definition. A stack overflow occurs when the size of the call stack exceeds the capacity allowed by the execution environment. This is usually due to a non-terminating recursive method.