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 = '()
]
[(cons 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
[(cons 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
copyh and resultCS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket
(define (sum-list l)
(match l
[empty 0]
[(cons h l) (+ h (sum-list l))]))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket
(define (sum-list l)
(match l
[`empty` 0]
[(cons 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]
[(cons h t) (+ h (sum-list l))]))
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
#lang racket
(define (sum-list l)
(match l
[(list) 0]
[(cons h t) (+ h (sum-list `l`))]))
t, but instead recursed on the original list ll 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))]))
cons in the second patternex.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)]
[((cons h1 l1) (cons 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
countthat builds counts fromnup tom.
CS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
We write a helper function
countthat builds counts fromnup 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
countthat builds counts fromnup 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))]))
countCS450 ☽ Recursion, nested definitions ☽ Lecture 4 ☽ Tiago Cogumbreiro
We move function
countto 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, parametertoremains 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
tofrom functioncountas it was constant throughout the execution. Variabletois captured/copied whencountis 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
errorto 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