Some Advanced Features of Procedures
Recursion
•	Recursive Calls
–	A procedure can call itself (Self Recursion)
–	A can call B, B calls C, etc,  Z calls A (Mutual Recursion)
•	Powerful Abstraction
–	Many functions are recursive in nature
–	Factorial, Fibonacci, etc.

        fact(0) = 1
        fact(n+1) = (n+1) * fact(n)

        fib(0) = 1
        fib(1) = 1
        fib(n+2) = fib(n+1) + fib(n)
•	Such functions can be directly encoded
Complex control Flow
•	Recursive functions abstracts out complex control flow
–	Different instance of the same procedure exists at a time
–	Termination and resumption of different instances correctly
–	Last called is exited first ( Last In First Out LIFO)
–	Use of stack data structure (stack overflow)
–	A lot of overhead in implementation
Factorial Example
Program fact
     Implicit none
     integer:: N, z
     read *, N
     call fct(N, z)
     print *, z
contains
    recursive subroutine fct(M, y)
    implicit none
    integer, intent(in):: M
    integer, intent(out):: y
    if (M >= 1) then
      call fct(M - 1, y)
      y = M * y
    else
      y = 1
    endif
   end subroutine
end program
Recursive Function
Program fact
   implicit none
   integer:: N, z
   read *, N
   z = fct(N)
   print *, z
contains
   recursive integer function fct(M) result(answer)
   implicit none
   integer:: M,  answer

   if (M /= 0) then
     answer = M * fct(M - 1)
   else
     answer = 1
   endif
   end function

end program
Fibonacci Numbers
Program fibonacci
   implicit none
   integer:: N, z
   read *, N
   call fib(N, z)
   print *, z
contains
   recursive subroutine fib(M, y)
   implicit none
   integer, intent(in):: M
   integer, intent(out):: y
   integer:: y1, y2
   if (M > 1) then
     call fib(M - 1, y1)
     call fib(M - 1, y2)
     y = y1 + y2
   else
     y = 1
   endif
   end subroutine
end program
Tower of Hanoi Problem
•	Initial Configuration
Final Configuration
Rules
•	Only one disc can be moved at a time
•	bigger disc never placed over a smaller one
•	only one temporary pole
•	How to solve the problem?
Divide and Conquer
•	Reduce the problem size! How?
•	Consider the following situation:
Sub problems
•	How to transfer smaller (n-1) discs from initial pole to temporary pole?
•	How to transfer smaller (n-1) discs to the final pole from temporary pole?
•	These two problems are similar but with the problem size reduced and the initial and final poles being different
•	How to solve the sub problems?
–	Reduce further down (recursion)
•	When (n-1) = 1, the problem becomes trivial
Sub problems
Algorithm hanoi_tower (ndisks, init_pole, spare_pole,                 
                                                                        fin_pole)
1.	If (ndisks > 0) then
		1.1 hanoi_tower(ndisks - 1, init_pole, fin_pole,  
                                                                  spare_pole)
		1.2 transfer_disk(init_pole, fin_pole)
		1.3 hanoi_tower(ndisks - 1, spare_pole, init_pole, 
                                                                          fin_pole)
	end
end 
•	When the first argument is 0, no action, only empty recursive calls
•	Simplify by removing the recursive calls for the case ndiscs = 1
Fortran Solution
•	requires modeling the problem domain
•	Need software models for all real objects
•	Discs, poles, movements etc.
•	Discs as numbers, poles as stacks, movements as pushes and pops
Quick Sort
•	quick sort is another sorting algorithm which when implemented properly gives the fastest known sorting algorithm for random inputs
•	useful for sorting arrays rather than lists
•	main idea – pick one element, put it in its correct position, all elements < than it to its left and others to its right
•	recursively sort left and right halves
•	expressed easily using recursion
Quick Sort
recursive subroutine quick_sort(a)
implicit none
integer, dimension(:), intent(inout) :: a
integer :: i,n
n = size(a)
if ( n > 1) then
call partition(a,i)
call quick_sort(a(:i-1))
call quick_sort(a(i+1:))
end if
contains
Partition
subroutine partition(a,j)
integer, dimension(:), intent(inout) :: a
integer,intent(out) :: j
integer :: i,temp
i = 1 ; j = size(a)
do
do
if ( i > j ) exit
if (a(i) > a(1)) exit
i = i+1
end do                
Partition
do
if ((j < i) .or. (a(j) <= a(1)))  exit
j = j-1
end do
if ( i >= j) exit
temp = a(i)
a(i) = a(j)
a(j) = temp
end do
temp = a(j) ; a(j) = a(1) ; a(1) = temp
end subroutine partition
end subroutine quick_sort
Tail Recursion
•	Any number of recursive calls
•	Complex control flow
•	Difficult to understand
•	Linear Recursion
•	Tail recursion
–	The recursive call occurs as the last statement
–	Can be easily translated to iterative programs
•	General recursive programs can also be translated to iterative programs
•	But this requires, in general, a stack (FIFO data structure)
•	Computationally expensive
Keyword Parameters
•	The actual parameter list should match the dummy parameter list in order
•	might prove to be cumbersome when argument lists are large
•	keyword argument is a solution to this problem
•	Suppose 
         test(first, second, third) 
                 ...
          end subroutine test
•	 the following calls are legal:
         test(3, 6, 7)
         test(first = 3, third = 7, second = 6)
         test(3, third = 7, second = 6)
•	Explicit interface for the procedure required
•	Declare it in a module which can be `used' by the calling routine
Optional Parameters
•	Parameters can be optional
•	Declare
–	integer, intent(in), optional:: limit
 
•	The actual argument for limit can be left out in a call and default values can be used
•	A logical function to test whether an optional argument is present or not
 
        if (PRESENT(limit) then 
             ...
        else
             ...
        endif