Functional Problem Solving (CSC 151 2016S) : EBoards
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] - [FAQ] [Teaching & Learning] [Grading] [Taking Notes] [Rubric]
Current: [Assignment] [EBoard] [Lab] [Outline] [Reading]
Sections: [Assignments] [EBoards] [Labs] [Outlines] [Readings] - [Examples] [Handouts]
Reference: [Setup] [Remote] [VM] [Errors] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Curtsinger (2016S)] [Davis (2013F)] [Rebelsky (2015F)] [Weinman (2014F)]
Misc: [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] - [Issue Tracker (Course)]
Thank you to the students who showed up so that we get a review session that other students can read over later.
Finding This Page
Overview
Topics
Types of recursive procedures you've seen/written
Types of questions
Will verifying preconditions be on the quiz?
No.
Do we still need to know what a precondition is?
Yes.
Could we look at the code from the recursion lab, problem 3?
An answer
(define list-length
(lambda (lst)
(if (null? lst)
0
(+ 1 (list-length (cdr lst))))))
Thought process: What's a simple case? Empty list! What if we can make someone else count a smaller list? Have them count everything but the first element, then add 1 to their result.
How does it work? Normal Scheme: Work inside-out, substitute body of procedure for call. Do the test for if first. (In the following, "=>" is supposed to be an arrow to show what comes next.)
(list-length '(3 1 "hello"))
=> (if (null? '(3 1 "hello")) 0 (+ 1 (list-length (cdr '(3 1 "hello"))))
=> (if #f 0 (+ 1 (list-length (cdr '(3 1 "hello")))))
=> (+ 1 (list-length (cdr '(3 1 "hello"))))
=> (+ 1 (list-length '(1 "hello")))
=> (+ 1 (if (null? '(1 "hello")) 0 (+ 1 (list-length (cdr '(1 "hello"))))))
=> (+ 1 (if #f 0 (+ 1 (list-length (cdr '(1 "hello"))))))
=> (+ 1 (+ 1 (list-length (cdr '(1 "hello")))))
=> (+ 1 (+ 1 (list-length '("hello"))))
=> (+ 1 (+ 1 (if (null? '("hello")) 0 (+ 1 (list-length (cdr '("hello")))))))
=> (+ 1 (+ 1 (if #f 0 (+ 1 (list-length (cdr '("hello")))))))
=> (+ 1 (+ 1 (+ 1 (list-length (cdr '("hello"))))))
=> (+ 1 (+ 1 (+ 1 (list-length '()))))
=> (+ 1 (+ 1 (+ 1 (if (null? '()) 0 (+ 1 (list-length (cdr '())))))))
=> (+ 1 (+ 1 (+ 1 (if #t 0 (+ 1 (list-length (cdr '())))))))
=> (+ 1 (+ 1 (+ 1 0)))
=> (+ 1 (+ 1 1))
=> (+ 1 2)
=> 3
When we run recursive procedures according to the rules of Scheme, we tend to build up a large amount of "future" work, hit the base case, and then do the future work.
What's a general thought process for designing recursive procedures over lists?
First, what's a case that even a CEO can do by themselves? (Usually: empty list, or a singleton list.) E.g., sum: empty list has a sum 0. Singleton list has a sum of the one value in the list.
Suppose we've solved the case for the cdr, how does that contribute to the overall answer? E.g., sum: If we've summed the remaining numbers, we just need to add the first number
As you may recall, in Scheme, evaluation happens from the inside out. We also "evaluate" a procedure call by substituting in the body of the procedure, with the formal parameters replaced by the actual paramters. Recursive procedures take advantage of these evaluation strategis by building up parts of the expression that get evaluated "later".
Consider the following definition of product.
(define product
(lambda (lst)
(if (null? lst)
1
(* (car lst) (product (cdr lst))))))
Here are the first few steps of the evaluation of (product '(4 2 3))
(product '(4 2 3))
=> (if (null? '(4 2 3)) ...)
=> (* (car '(4 2 3)) (product (cdr '(4 2 3))))
=> (* 4 (product (cdr '(4 2 3))))
=> (* 4 (product '(2 3)))
=> (* 4 (if (null? '(2 3) ...)))
Show the remaining steps
Consider the following implementation of largest, which
is intended to find the largest element in a list.
(define largest
(lambda (lst)
(if (null? lst)
0
(max (car lst) (largest lst)))))
There are at least two errors in this procedure. Identify them and indicate how to fix them.
Fill in the blanks in the following procedure, which tallies the number of strings in a list.
(define tally-strings
(lambda (lst)
(cond
[__________
0]
[__________
(+ 1 (tally-strings (cdr lst)))]
[else
_______________________________])))
Fill in the blanks in the following procedure, which tallies the number of strings in a list.
(define tally-strings
(lambda (lst)
(if (null? lst)
_______
(+ (if __________ 1 0)
(tally-strings (cdr lst))))))
Fill in the blanks in the following procedure, which tallies the number of strings in a list.
(define tally-strings
(lambda (lst)
(if _______
0
(let ([tally-car ___________]
[tally-cdr (tally-strings ________)])
(+ tally-car tally-cdr)))))
Fill in the blanks in the following procedure, which selects all the strings in a list.
(define select-strings
(lambda (lst)
(cond
[(null? lst)
_________]
[(string? (car lst))
(__________________ (select-strings (cdr lst)))]
[else
_______________________________])))
Issue 1: What value do we return in the base case? The list of all the strings in the empty list contains ...?
Issue 2: Suppose the car of the list is a string and we've gotten all the strings in the cdr. What should we do? Example: (select-strings '("a" 2 "c" '() "d" 4 5 "e")), "a" is a string. '("c" "d" "e") are all the remaining strings. What next?
Issue 3: What should we do if the car is not a string? E.g., '(select-strings '(1 "a" 2 "c" '() "d")).
(define select-strings
(lambda (lst)
(cond
[(null? lst)
null]
[(string? (car lst))
(cons (car lst) (select-strings (cdr lst)))]
[else
(select-strings (cdr lst))])))
Write the 6P-style documentation for the following procedure.
(define whatzitdo
(lambda (x)
(if (null? (cdr x))
(car x)
(let ([y (car x)]
[z (whatzitdo (cdr x))])
(if (< y z)
y
z)))))
Write the 6P-style documentation for the following procedure.
(define whatzitdo
(lambda (x)
(if (null? x)
null
(cons (irgb-bluer (car x))
(whatzitdo (cdr x))))))
(map irgb-bluer x).Suppos we want a procedure that finds the value in a list that has the largest absolute value. For example,
> (largest-absolute-value (list 5 2 -3 4))
5
> (largest-absolute-value (list 5 2 -3 4 -7 1))
-7
> (largest-absolute-value (list 0))
0
> (largest-absolute-value '())
ERROR
> (largest-absolute-value (list 3 19))
19
Finish the definition of largest-absolute-value.
(define largest-absolute-value
(lambda (lst)
(let ([current (car lst)])
(if _____________
current
(let ([alternate (largest-absolute-value (cdr lst))])
(if ______________
current
alternate))))))
Base case test: If there's only one element. One way to test that
(= 1 (length lst)). But that's inefficient. So we prefer
(null? (cdr lst))
(define largest-absolute-value
(lambda (lst)
(let ([current (car lst)])
(if (null? (cdr lst))
current
(let ([alternate (largest-absolute-value (cdr lst))])
(if (> (abs current) (abs alternate))
current
alternate))))))
We could also have written this as follows, but that repeats code.
(define largest-absolute-value
(lambda (lst)
(if (null? (cdr lst))
(car lst)
(let ([alternate (largest-absolute-value (cdr lst))])
(if (> (abs (car lst)) (abs alternate))
(car lst)
alternate)))))
Can we talk about copy/paste?