Lecture 11
Recursion - Approaching Complex Problems in a Different Way
Difficulty curve of the course
Writing
functions
Lists and
higher order functions
Recursive functions
Imperative programming
and object-oriented programming
Programming as com/position
Levels of abstraction
computing tip
multiplication
addition
single-digit addition
counting
…
The story so far
We’ve been focusing on
Algorithm design
How do we write an iterator?
Universality
(Actually, Church proved you don't even need if expressions!)
Summing a list
Simple example: summing a list
> (sum-list (list 1 2 3))
6
Simple list accessors
(first list), (second list), …, (eighth list)�;; first, etc. : (listof T) -> T��Extracts the specified element of list
(rest list)�;; rest: (listof T) -> (listof T)
�Returns all but the first element of list
Summing a 2-element list
;; sum-list-2:
;; (list number number) -> number
;; Sums a two-element list
(define sum-list-2
(lambda (a-list)
(+ (first a-list)
(second a-list)))
(check-expect (sum-list-2 (list 1 2))
3)
Summing a 3-element list
(define sum-list-2
(lambda (a-list)
(+ (first a-list)
(second a-list))))
(define sum-list-3
(lambda (a-list)
(+ (first a-list)
(second a-list)
(third a-list))))
Summing a 3-element list
(define sum-list-2
(lambda (a-list)
(+ (first a-list)
(second a-list))))
(define sum-list-3
(lambda (a-list)
(+ (first a-list)
(sum-list-2 (rest
a-list)))))
Summing a 4-element list
(define sum-list-2
(lambda (a-list)
(+ (first a-list)
(second a-list))))
(define sum-list-3
(lambda (a-list)
(+ (first a-list)
(sum-list-2
(rest a-list)))))
(define sum-list-4
(lambda (a-list)
(+ (first a-list)
(sum-list-3
(rest a-list)))))
Summing a 5-element list
(define sum-list-2
(lambda (a-list)
(+ (first a-list)
(second a-list))))
(define sum-list-3
(lambda (a-list)
(+ (first a-list)
(sum-list-2
(rest a-list)))))
(define sum-list-4
(lambda (a-list)
(+ (first a-list)
(sum-list-3
(rest a-list)))))
(define sum-list-5
(lambda (a-list)
(+ (first a-list)
(sum-list-4
(rest a-list)))))
We can sum any number of elements this way
(define sum-list-2
(lambda (a-list)
(+ (first a-list)
(second a-list))))
(define sum-list-3
(lambda (a-list)
(+ (first a-list)
(sum-list-2
(rest a-list)))))
(define sum-list-4
(lambda (a-list)
(+ (first a-list)
(sum-list-3
(rest a-list)))))
(define sum-list-5
(lambda (a-list)
(+ (first a-list)
(sum-list-4
(rest a-list)))))
(define sum-list-6
(lambda (a-list)
(+ (first a-list)
(sum-list-5
(rest a-list)))))
(define sum-list-7
(lambda (a-list)
(+ (first a-list)
(sum-list-6
(rest a-list)))))
(define sum-list-8
(lambda (a-list)
(+ (first a-list)
(sum-list-7
(rest a-list)))))
(define sum-list-9
(lambda (a-list)
(+ (first a-list)
(sum-list-8
(rest a-list)))))
Summing a list under the substitution model
A quick aside: quoting lists
Note: I'm going to use quoting to simplify the following slides, it's never required or necessary to quote.
Warning: this works with CONSTANTS but provides strange behavior with more complex expressions.
Execution under the substitution model
(sum-list-4 (list 1 2 3 4))
(sum-list-3 (rest '(1 2 3 4))))
(sum-list-3 '(2 3 4)))
(+ (first '(2 3 4))
(sum-list-2 (rest '(2 3 4)))))
(+ 2
(sum-list-2 '(3 4))))
(+ 2
(+ (first '(3 4))
(sum-list-1 (rest '(3 4)))))
(+ 2
(+ 3
(sum-list-1 '(4)))))
(+ 2
(+ 3
(+ (first '(4))
(sum-list-0
(rest '(4)))))))
(+ 2
(+ 3
(+ 4
(sum-list-0
'())))))
Execution under the substitution model
(+ 2
(+ 3
(+ 4
0))))
(+ 2
(+ 3
4)))
(+ 2
7))
9)
But this is still a dumb way to write it
(define sum-list-0
(lambda (a-list)
0))
(define sum-list-1
(lambda (a-list)
(+ (first a-list)
(sum-list-0 (rest a-list)))))
(define sum-list-2
(lambda (a-list)
(+ (first a-list)
(sum-list-1 (rest a-list))))
(define sum-list-3
(lambda (a-list)
(+ (first a-list)
(sum-list-2 (rest a-list)))))
Recursion
Recursion
General outline
Recursively�summing a list
We can sum any number of elements this way
(define sum-list-0
(lambda (a-list)
0))
(define sum-list-1
(lambda (a-list)
(+ (first a-list)
(sum-list-0 (rest a-list)))))
(define sum-list-2
(lambda (a-list)
(+ (first a-list)
(sum-list-1 (rest a-list))))
(define sum-list-3
(lambda (a-list)
(+ (first a-list)
(sum-list-2 (rest a-list)))))
(define sum-list-4
(lambda (a-list)
(+ (first a-list)
(sum-list-3 (rest a-list)))))
(define sum-list-5
(lambda (a-list)
(+ (first a-list)
(sum-list-4 (rest a-list)))))
(define sum-list-6
(lambda (a-list)
(+ (first a-list)
(sum-list-5 (rest a-list))))
(define sum-list-7
(lambda (a-list)
(+ (first a-list)
(sum-list-6 (rest a-list)))))
A better way to write it
;; sum-list:
;; (listof number) -> number
;; Total of elements of a list
(define sum-list
(lambda (a-list)
(if (empty? a-list)
0
(+ (first a-list)
(sum-list (rest a-list))))))
(check-expect
(sum-list (list 1 2 3 4))
10)
(check-expect (sum-list (list)) 0)
Note: in the video, this function call was missing
Execution under the substitution model
0
(+ (first '(1 2 3 4))
(sum-list (rest '(1 2 3 4)))))
0
(+ (first '(1 2 3 4))
(sum-list (rest '(1 2 3 4)))))
(sum-list (rest '(1 2 3 4)))
(+ 1
(sum-list '(2 3 4)))
(if (empty? '(2 3 4))
0
(+ (first '(2 3 4))
(sum-list (rest '(2 3 4))))))
(if false
0
(+ (first '(2 3 4))
(sum-list (rest ''(2 3 4))))))
(+ (first '(2 3 4))
(sum-list (rest '(2 3 4)))))
(+ 2
(sum-list '(3 4))))
Execution under the substitution model
(+ 2
(sum-list '(3 4))))
(+ 2
(if (empty? '(3 4))
0
(+ (first '(3 4))
(sum-list (rest '(3 4)))))))
(+ 2
(if false
0
(+ (first '(3 4))
(sum-list (rest '(3 4)))))))
(+ 2
(+ (first '(3 4))
(sum-list (rest '(3 4))))))
(+ 2
(+ 3
(sum-list '(4)))))
(+ 2
(+ 3
(if (empty? '(4))
0
(+ (first '(4))
(sum-list
(rest '(4))))))))
Execution under the substitution model
(+ 2
(+ 3
(+ 4
(sum-list '())))))
(+ 2
(+ 3
(+ 4
(if (empty? '())
0
(+ (first '())
(sum-list
(rest '()))))))))
(+ 2
(+ 3
(if false
0
(+ (first '(4))
(sum-list
(rest '(4))))))))
(+ 2
(+ 3
(+ (first '(4))
(sum-list
(rest '(4)))))))
Execution under the substitution model
(+ 2
(+ 3
(+ 4
(if true
0
(+ (first '())
(sum-list
(rest '()))))))))
(+ 2
(+ 3
(+ 4
0))))
(+ 2
(+ 3
(+ 4
0))))
(+ 2
(+ 3
4)))
(+ 2
7))
9)
Basic template�For recursion
Basic template for recursion
(define function
(lambda (args)� (if easy-case?� solve-easy-case� (fix-solution� (function simplified))))
Basic template for recursion
(define function
(lambda (args …) � (if easy-case?� solve-easy-case� (combine solve-one-part
(function
other-part)))))
Look familiar?
;; sum-list:
;; (listof number) -> number
;; Total of elements of a list
(define sum-list
(lambda (sum-list)
(if (empty? list)
0
(+ (first list)
(sum-list (rest list))))))
(check-expect
(sum-list (list 1 2 3 4))
10)
(check-expect (sum-list (list)) 0)
Correction! (missing function call)
Writing foldl/r
Using recursion
How do we write foldr?
(define sum-list
(lambda (a-list)
(if (empty? a-list)
0
(+ (first a-list)
(sum-list (rest a-list))))))
;; foldr: (X X -> X) X (listof X) -> X
;; Aggregates elements of list
;; using proc.
(define foldr
(lambda (func start list)
???))
How do we write foldr?
(define sum-list
(lambda (a-list)
(if (empty? a-list)
0
(+ (first a-list)
(sum-list (rest a-list))))))
;; foldr: (X X -> X) X (listof X) -> X
;; Aggregates elements of list
;; using func.
(define foldr
(lambda (func start list)
(if (empty? list)
start
(func (first list)
(foldr func
start
(rest list))))))
Writing length
Using recursion
Example
;; length: (listof any) -> number�;; Returns number of elements in list
Example
;; length: (listof any) -> number�;; Returns number of elements in list
(define length�(λ (list) � (if (empty? list)� 0� (+ 1� (length (rest list))))))
(check-expect (length (list 1 2 3))� 3)
Execution in the substitution model
(rest '())))))))
(rest '())))))))
Sussman-form definitions
This is a good time to mention Sussman-form definitions
(define (function-name inputs …)�output)
Writing iterated-beside
Using recursion
Example
;; iterated-beside: (number -> picture) number -> picture
;; Makes a horizontal series of pictures using�;; generator function
Example
(define (iterated-beside func count)�(if (= count 0)� empty-image ; this is a magic var with a blank image
… to be filled in …))
Example
(define (iterated-beside func count)�(if (= count 0)� empty-image� (func count)))
Example
(define (iterated-beside func count)�(if (= count 0)� empty-image
(combine (func count)� (iterated-beside func (- count 1)))))
Example
(define (iterated-beside func count)�(if (= count 0)� empty-image
(beside (func (- count 1)) ; we need to subtract 1 here� (iterated-beside func (- count 1)))))
Execution is recursive
Rules of computation in Racket
Look at the expression
Example: running code
Is it a primitive expression?
Some code that almost works
(define interpreter
(λ (expression)
(if (number? expression)
expression
(if (name? expression)
(look-it-up expression)
(local [(define values
(map interpreter expression))]
(apply (first values)
(rest values)))))))
This is a teaser for the students completing the advanced tutorials.