Exploring Languages
with Interpreters
and Functional Programming

Chapter 9
Recursion Styles

H. Conrad Cunningham

11 September 2018

Copyright (C) 2017, 2018, H. Conrad Cunningham

Acknowledgements: I originally created these slides in Fall 2017 to accompany what is now Chapter 9, Recursion Styles and Efficiency, in the 2018 version of the textbook Exploring Languages with Interpreters and Functional Programming.

Browser Advisory: The HTML version of this document may require use of a browser that supports the display of MathML. A good choice as of September 2018 is a recent version of Firefox from Mozilla.

Recursion Styles and Efficiency

Lecture Goals

Linear Recursion

Nonlinear Recursion

Linear vs. Nonlinear

Backward Recursion

Forward Recursion (1)

Forward Recursion (2)

    factIter :: Int -> Int -> Int  -- auxiliary function, two args
    factIter 0 r         = r
    factIter n r | n > 0 = factIter (n-1) (n*r)  -- forward recursive

Tail Recursion (1)

Tail Recursion (2)

    fib2 :: Int -> Int
    fib2 n | n >= 0 = fibIter n 0 1 
        where 
            fibIter 0 p q         = p   -- two accumulators
            fibIter m p q | m > 0 = fibIter (m-1) q (p+q)

Logarithmic Recursion (1)

Logarithmic Recursion (2)

    expt2 :: Integer -> Integer -> Integer
    expt2 b n | n < 0 = error ("expt2 undefined for negative exponent" 
                                   ++ show n )
    expt2 b n         = exptIter n 1
        where exptIter 0 p = p
              exptIter m p = exptIter (m-1) (b*p) -- tail recursive

Logarithmic Recursion (3)

Logarithmic Recursion (3)

    expt3 :: Integer -> Integer -> Integer
    expt3 _ n | n < 0 = error ("expt3 undefined for negative exponent"
                               ++ show n )
    expt3 b n         = exptAux n
        where exptAux 0 = 1
               exptAux n
                   | even n    = let exp = exptAux (n `div` 2) in -- local
                                     exp * exp      -- backward recursive
                   | otherwise = b * exptAux (n-1)  -- backward recursive

Local Definitions

let Definitions (1)

let local_definitions in expression

    f :: [Int] -> [Int]
    f [] = []
    f xs = let square a = a * a 
               one      = 1 
               (y:ys)   = xs 
           in (square y + one) : f ys 

let Definitions (2)

    f :: [Int] -> [Int]
    f [] = []
    f xs = let square a = a * a 
               one      = 1 
               (y:ys)   = xs 
           in (square y + one) : f ys 

where Definitions

    g :: Int -> Int
    g n | check3 == x = x
        | check3 == y = y
        | check3 == z = z * z
                      where check3 = n `mod` 3
                            x      = 0
                            y      = 1
                            z      = 2

Local Defs and Efficiency

Key Ideas

Source Code