Comp 112

Lecture 9

Recursive Functions

2018.03.27

Recursive Functions

Example: Countdown

Many programming problems can be solved by using either iteration or recursion:

nn,(n1),(n2),,1,go!countdown(n1)countdownnn \quad ⟼ \quad \overbrace{n , \underbrace{(n−1) , (n−2) , ⋯ , 1 , \mathrm{go!}} _ {\mathrm{countdown} ~ (n−1)} } ^ {\mathrm{countdown} ~ n}

Iteration vs Recursion

Think Locally, Act Globally

To solve a problem by recursion:

This is enough to solve any problem so long as you:

Example: Factorial

"""
signature: int -> int
precondition: n >= 0
returns the factorial of the argument
"""

nn×(n1)×(n2)××1factorial(n1)factorial(n)n \quad ⟼ \quad \overbrace{n × \underbrace{(n−1) × (n−2) × ⋯ × 1} _ {\mathrm{factorial} ~ (n−1)} } ^ {\mathrm{factorial} ~ (n)}

Heads and Tails

A common strategy for writing recursive functions for lists:

This strategy also works for strings.

Example: Recursive List Summing

"""
signature: list (int) -> int
sums the numbers in a list
"""

[n0,n1,n2,,nk]n0+n1+n2++nksum(ns[1:])sum(ns)[n_0 , n_1 , n_2 , ⋯ , n_k] \quad ⟼ \quad \overbrace{n_0 + \underbrace{n_1 + n_2 + ⋯ + n_k} _ {\mathrm{sum} ~ (ns [1:])} } ^ {\mathrm{sum} ~ (ns)}

Example: Recursive List Reversal

"""
signature: any a . list (a) -> list (a)
reverses a list of any type
"""

[x0,x1,x2,,xn][xn,,x2,x1,x0]=[xn,,x2,x1]reverse(xs[1:])+[x0]reverse(xs)[x_0 , x_1 , x_2 , ⋯ , x_n] \quad ⟼ \quad [x_n, ⋯ , x_2 , x_1 , x_0] ~ = ~ \overbrace{\underbrace{[x_n, ⋯ , x_2 , x_1]} _ {\mathrm{reverse} ~ (xs [1:])} + [x_0] } ^ {\mathrm{reverse} ~ (xs)}

Recursive Specifications

A palindrome is a word that reads the same forward as backward.

We can characterize the property of being a palindrome with the following specification:

This specification is recursive because in the second case we refer to the same property that we are describing.

It’s easy to turn this recursive specification into a recursive predicate function.

Self-Similarity

A self-similar shape is one whose description is recursive, i.e. it contains a reference to itself.

Very simple recursive descriptions can produce interesting self-similar shapes

Here’s a helper-function for speeding up deeply-nested recursive drawings:

e.g.

Fractal Triangles

Starting with an equilateral triangle

we can draw a scaled-down version of it in each of its three corners

and scaled down version of those in each of their corners

and so on and so on…

The result is called a Sierpinski triangle:

Once we have figured out its recursive structure, we can optimize it by pruning the empty branch:

To Do This Week: