Warning This class is being recorded (and transcribed).
Approximate overview
Academic
Cultural
Peer
Wellness
Misc
Topics
Timing and such
Studying for quizzes
Sample question
Refactor redundancy and add clarity in computations with let-bindings.
Consider the following procedure that contains some repetitious code.
;;; (letter->number ch) -> either integer? boolean?
;;; ch : char?
;;; Converts ch to the corresponding number in the English alphabet.
;;; (1 for #\a or #\A, 2 for #\b or #\B, etc.). Returns false (#f)
;;; if ch is not a letter in the English alphabet.
(define letter->number
(lambda (ch)
(cond
[(<= (char->integer #\a) (char->integer ch) (char->integer #\z))
(+ 1 (- (char->integer ch) 97))]
[(<= (char->integer #\a) (+ (char->integer ch) 32) (char->integer #\z))
(+ 1 (- (+ (char->integer ch) 32) 97))]
[else #f])))
(check-equal? (map letter->number (string->list "abcde"))
'(1 2 3 4 5)
"First five lowercase letters")
(check-equal? (map letter->number (string->list "ABCDE"))
'(1 2 3 4 5)
"First five uppercase letters")
(check-equal? (map letter->number (string->list "XYZ"))
'(24 25 26)
"Last three uppercase letters")
(check-equal? (map letter->number (string->list "xyz"))
'(24 25 26)
"Last three lowercase letters")
(check-equal? (letter->number #\.)
#f
"Not a letter")
As you know, we should avoid redundant computations and magic numbers. Using
local bindings (let or let*), remove the redundant computations and magic
numbers from letter->number. You need not change the primary stucture
of the cond, but you should not compute the same value twice.
Note: In case you didn’t know, 32 is the result of subtracting the
collating sequence number of #\A from the collating sequence number
of #\a. By adding 32, we switch from uppercase to lowercase. And
97 seems to be the collating sequence number of #a, but we probably
shouldn’t count on that.
select-oddsHere’s a way that Ellie and Ella and Sam tried helping some folks
with select-odds. I like it because it emphasizes the recursion.
(define select-odds
(lambda (nums)
(if (null? nums)
null
(let ([remaining-odds (select-odds (cdr nums))])
(if (and (integer? (car nums)) (odd? (car nums)))
(cons (car nums)
remaining-odds)
remaining-odds)))))
longest-stringI like longest-string because it suggests multiple approaches.
#|
Implement a procedure, `(longest-word words)`, that takes a nonempty list
of strings as input and finds the longest string in the list. If there
are multiple strings that have the same length and are longer than any
other strings in the list, you can return any of them.
You may not use `sort` or `reduce` to solve this problem. (You've
guessed it; this procedure helps you understand how one of the
forms of `reduce` might be implemented.)
|#
;;; (longest-word words) -> string?
;;; words : list-of string? (nonempty)
(define longest-word
(lambda (words)
???))
A straightforward way. Compare the recursive result to the first word and take the longer of the two.
(define longest-word
(lambda (words)
(if (singleton? words)
(car words)
(if (> (string-length (car words))
(string-length (longest-word (cdr words))))
(car words)
(longest-word (cdr words))))))
The straightfoward way, rethought with a helper procedure to avoid duplicating work. In my world, this more closely matches the English-language description.
(define longer-word
(lambda (word1 word2)
(if (> (string-length word1) (string-length word2))
word1
word2)))
(define longest-word
(lambda (words)
(if (singleton? words)
(car words)
(longer-word (car words) (longest-word (cdr words))))))
The straightforward way, using a local binding to name the recursive result.
(define longest-word
(lambda (words)
(if (singleton? words)
(car words)
(let ([longest-remaining (longest-word (cdr words))])
(if (> (string-length (car words)) (string-length longest-remaining))
(car words)
longest-remaining)))))
Twisting things around: Compare the first two words.
(define longest-word
(lambda (words)
(if (singleton? words)
(car words)
(if (> (string-length (car words)) (string-length (car (cdr words))))
(longest-word (cons (car words) (cdr (cdr words))))
(longest-word (cdr words))))))
TPS: Load the eboard, look at the variants. Which do you prefer? Why?
reduce-left) works.longer-word helps with readability.(define longest-word
(lambda (words)
(if (singleton? words)
(car words)
(longest-word (cons (longer-word (list-ref words 0) (list-ref words 1))
(cddr words))))))
awesumConsider the problem of adding up all the numbers in a nested list of a form something like the following.
'(3 (4 5) (6 (7 (8 9) (10 (11)))))
As you’ve seen in the mini-project, we call such lists “deeply nested”. A deeply nested list of numbers is a list that contains only numbers and deeply nested lists of numbers.
;;; (awesum numbers) -> number?
;;; numbers : a deeply nested list of numbers
;;; Add up all of the numbers in numbers.
(define awesum
(lambda (numbers)
???))
We’ll assume that numbers is correctly formed (that is, it is a list
of either numbers or deeply nested lists of numbers).
TPS: Base case, easy recursive case, harder recursive case.
(test-equal? "empty list" (awesum '()) 0)
(test-equal? "simple list" (awesum '(1 2 1)) 4)
(test-equal? "slightly nested list" (awesum '(4 (2 3) 5)) 14)
(test-equal? "more deeply nested list"
(awesum '(1 ((2) 3 () (4 (5 (6))) (7))))
28)
(define awesum
(lambda (numbers)
(if (null? numbers)
0
(if (number? (car numbers))
(+ (car numbers) (awesum (cdr numbers)))
(+ (awesum (car numbers)) (awesum (cdr numbers)))))))
(awesum '(1 ((2) 3 () (4 (5 (6))) (7)))) --> (+ 1 (awesum '((2) 3 () (4 (5 (6))) (7)))) --> (+ 1 (+ (awesum '(2)) (awesum '(3 () (4 (5 (6))) (7))))) --> (+ 1 (+ (+ 2 (awesum '())) (awesum '(3 () (4 (5 (6))) (7))))) --> (+ 1 (+ (+ 2 0) (awesum '(3 () (4 (5 (6))) (7))))) --> (+ 1 (+ 2 (awesum '(3 () (4 (5 (6))) (7))))) --> (+ 1 (+ 2 (+ 3 (awesum '(() (4 (5 (6))) (7)))))) --> (+ 1 (+ 2 (+ 3 (+ (awesum '()) (awesum '((4 (5 (6))) (7))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (awesum '((4 (5 (6))) (7))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ (awesum '(4 (5 (6)))) (awesum '((7)))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ (+ 4 (awesum (5 (6)))) (awesum '((7)))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ (+ 4 (+ 5 (awesum '(6)))) (awesum '((7)))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ (+ 4 (+ 5 (+ 6 (awesum '())))) (awesum '((7)))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ (+ 4 (+ 5 (+ 6 0))) (awesum '((7)))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ (+ 4 (+ 5 6)) (awesum '((7)))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ (+ 4 11) (awesum '((7)))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ 15 (awesum '((7)))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ 15 (+ (awesum '(7)) (awesum '()))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ 15 (+ (+ 7 (awesum '())) (awesum '()))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ 15 (+ (+ 7 0) (awesum '()))))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ 15 (+ 7 0)))))) --> (+ 1 (+ 2 (+ 3 (+ 0 (+ 15 7))))) --> (+ 1 (+ 2 (+ 3 (+ 0 22)))) --> (+ 1 (+ 2 (+ 3 22))) --> (+ 1 (+ 2 25)) --> (+ 1 27) --> 28 ```
I’m confused as to how the “partof” label applies to numeric recursion. I understand how it applies in regard to lists, but it just doesn’t make sense to me in the examples given from the reading.
For numeric recursion,
partofis almost always just the number.
I’m getting an error with rgb-red.
It should be
color-red.
Can I have an extension until Saturday night?
Yes.
Can we assume that all sublists have at least two elements?
For an M, yes. For an E, you must handle singleton lists.
Hint: Write something that checks for these cases, does the appropriate thing for them, and applies
besideorabovein the remaining cases. (I think that’s the only time it really matters.)