CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
(define (copy l) (match l [(list) ; input = '() (list) ; expected output = '() ] [(list h l ...) ; input = (list 1 2 3) ; h = 1 ; l = (list 2 3) (define result (copy l)) ; result = (list 2 3) (cons h result) ; expected output = (list 1 2 3) ]))
(define (copy l) l)
would be a simpler solution, but we're trying to
illustrate a recursion pattern.CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
(require rackunit)(check-equal? 10 (sum-list (list 1 2 3 4)))(check-equal? 0 (sum-list (list)))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
(define (sum l) (match l [(list) ; input = '() 0] ; expected output = 0 [(list h l ...) ; input = '(1 2 3 4) ; h = 1 ; l = '(2 3 4) ; result = (sum (list 2 3 4)) = 2 + 3 + 4 = 9 (define result (sum l)) (+ h result) ])) ; expected output = (+ 1 9) = 10
copy
h
and result
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket(define (sum-list l) (match l [empty 0] [(list h l ...) (+ h (sum-list l))]))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket(define (sum-list l) (match l [empty 0] [(list h l ...) (+ h (sum-list l))]))
match
consider empty
to be defined as (define empty (list))
, not as a keywordempty
means: anything you find assign it to a variable called empty
; same as writing [x 0]
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket(define (sum-list l) (match l [(list) 0] [(list h t ...) (+ h (sum-list l))]))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket(define (sum-list l) (match l [(list) 0] [(list h t ...) (+ h (sum-list l))]))
t
, but instead recursed on the original list l
l
as the rest of the list, and make this error impossible.CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket(define (sum-list l) (match l [(list) 0] [(h l ...) (+ h (sum-list l))]))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket(define (sum-list l) (match l [(list) 0] [(h l ...) (+ h (sum-list l))]))
list
in the second pattern ex.rkt:5:5: match: syntax error in pattern in: (h l ...) location...: ex.rkt:5:5
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
(require rackunit)(check-equal? (list) (count-down 0))(check-equal? (list 3 2 1) (count-down 3))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
(require rackunit)(check-equal? (list) (count-down 0))(check-equal? (list 3 2 1) (count-down 3))
#lang racket(define (count-down n) (cond [(<= n 0) (list)] [else (cons n (count-down (- n 1)))]))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
(require rackunit)(check-equal? (list (cons 3 30) (cons 2 20) (cons 1 10)) (zip (list 3 2 1) (list 30 20 10)))(check-equal? (list (cons 3 30) (cons 2 20) (cons 1 10)) (zip (list 3 2 1) (list 30 20 10 5 4 3 2 1)))(check-equal? (list (cons 3 30) (cons 2 20) (cons 1 10)) (zip (list 3 2 1 90 180 270) (list 30 20 10)))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket(define pair list) ; Encode a pair as a list(define (zip l1 l2)
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket(define pair list) ; Encode a pair as a list(define (zip l1 l2)
(match* (l1 l2) [((list) _) (list)] [(_ (list)) (list)] [((list h1 l1 ...) (list h2 l2 ...)) (cons (pair h1 h2) (zip l1 l2))]))
match*
to pattern match two values at onceCS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
Our goal is to build a list from 1 up to some number. Here is a template of our function and a test case for us to play with. For the sake of simplicity, we will not handle non-positive numbers.
#lang racket(define (countup-from1 x) #f)(require rackunit)(check-equal? (list 1) (countup-from1 1))(check-equal? (list 1 2) (countup-from1 2))(check-equal? (list 1 2 3 4 5) (countup-from1 5))
Hint: write a helper function
count
that builds counts fromn
up tom
.
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
We write a helper function
count
that builds counts fromn
up tom
.
#lang racket(define (countup-from1 x) (count 1 x))(define (count from to) (cond [(equal? from to) (list to)] [else (cons from (count (+ 1 from) to))]))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
We write a helper function
count
that builds counts fromn
up tom
.
#lang racket(define (countup-from1 x) (count 1 x))(define (count from to) (cond [(equal? from to) (list to)] [else (cons from (count (+ 1 from) to))]))
count
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
We move function
count
to be internal to functioncountup-from1
, as it is a helper function and therefore it is good practice to make it private tocountup-from1
.
(define (countup-from1 x) ; Internally defined function, not visible from ; the outside (define (count from to) (cond [(equal? from to) (list to)] [else (cons from (count (+ 1 from) to))])) ; The same call as before (count 1 x))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
Nest functions:
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
Nested definitions bind a variable within the body of a function and are only visible within that function (these are local variables)
#lang racket(define (f x) (define z 3) (+ x z))(+ 1 z) ; Error: z is not visible outside function f
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
Nested definitions silently shadow any already defined variable
#lang racket(define z 10)(define (f x) (define x 3) ; Shadows parameter (define z 20) ; Shadows global (+ x z))(f 1) ; Outputs 23
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
It is an error to re-define local variables
#lang racket(define (f b) ; OK to shadow a parameter (define b (+ b 1)) (define a 1) ; Not OK to re-define local variables ; Error: define-values: duplicate binding name (define a (+ a 1)) (+ a b))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
Notice that we have some redundancy in our code. In function
count
, parameterto
remains unchanged throughout execution.
(define (countup-from1 x) ; Internally defined function, not visible from ; the outside (define (count from to) (cond [(equal? from to) (list to)] [else (cons from (count (+ 1 from) to))])) ; The same call as before (count 1 x))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
We removed parameter
to
from functioncount
as it was constant throughout the execution. Variableto
is captured/copied whencount
is defined.
(define (countup-from1 to) ; Internally defined function, not visible from ; the outside (define (count from) (cond [(equal? from to) (list to)] [else (cons from (count (+ 1 from)))])) ; The same call as before (count 1))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
Finding the maximum element of a list.
#lang racket(define (max xs) (cond [(empty? xs) (error "max: expecting a non-empty list!")] [(empty? (rest xs)) (first xs)] ; The list only has one element (the max) [(> (first xs) (max (rest xs))) (first xs)] ; The max of the rest is smaller than 1st [else (max (rest xs))])) ; Otherwise, use the max of the rest; A simple unit-test(require rackunit)(check-equal? 10 (max (list 1 2 10 4 0)))
We use function
error
to abort the program with an exception.
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
Finding the maximum element of a list.
Let us benchmark max
with sorted list (worst-case scenario):
Whenever we add an element we double the execution time. Why?
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
Whenever we hit the else branch (because we can't find the maximum), we re-compute the max element.
(define (max xs) (cond [(empty? xs) (error "max: expecting a non-empty list!")] [(empty? (rest xs)) (first xs)] ; The list only has one element (the max) [(> (first xs) (max (rest xs))) (first xs)] ; The max of the rest is smaller than 1st [else (max (rest xs))])) ; Otherwise, use the max of the rest
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
We use a local variable to cache a duplicate computation.
(define (max xs) (cond [(empty? xs) (error "max: expecting a non-empty list!")] [(empty? (rest xs)) (first xs)] [else (define rest-max (max (rest xs))) ; Cache the max of the rest (cond [(> (first xs) rest-max) (first xs)] [else rest-max])]))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |