EBoard 22: Pause for breath: Reflections on recursion (Section 3)

Warning! You are being recorded and transcribed, provided the technology is working correctly.

Approximate optimistic overview

  • Administrative stuff
  • Notes on MP6
  • Q&A
  • Notes on the local bindings quiz
  • Notes on recent labs
  • A few problems (if there’s time)

Administrative stuff

Introductory notes

  • Today is a “talk and TPS day”.
  • All the MPs have been returned (finally). Let me know if you need extra time for othe next redo.
  • All the tokens earned are in place. We’ll look quickly at how you tell how you did.
  • It appears that some graders were a bit over-cautious on the edge case requirements for MP2 (and, perhaps, elsewhere). If you’d like me to review that issue, let me know.
  • Because the style LA was particularly painful, I’ll plan a makeup style quiz that you should be able to do in fifteen minutes for next week. Make sure to read the handout on program style before that quiz. Take notes for yourself.
  • Wednesday’s quiz also did not go well, so we’ll be talking about that.

Upcoming activities

Scholarly

  • Friday, 28 March 2025, 5:00–6:10 p.m., HSSC A2231. Conversations in the Humanities: Leadership in the Age of AI
  • Thursday, 3 April 2025, 11am–noon, JRC 101. Scholars’ Convocation: LeAnne Howe “A Choctaw In King Abdullah’s Court”
    • Also important, but not directly relevant to this class.

Artistic

  • Friday, 28 March 2025: 5:00–5:45 p.m., HSSC S1325. Kinetic Challenge Information Session.

Multicultural

  • Friday, 28 March 2025, 4:00–5:00 p.m., HSSC N1170 (Global Living Room). Middle of Everywhere: Why you should visit Nepal
  • Friday, 28 March 2025, 5:30 .m., HSSC N2116. A Latine-based dinner and conversation with Dr. Gabriella Soto.
    • Dinner provided.

Peer

Musical, theatric, sporting, and academic events involving this section’s students are welcome.

Wellness

  • Friday, 28 March 2025, 6:00 p.m.–8:00 p.m., Aux Gym. Badminton Club (Smash that bird!)
  • Friday, 28 March 2025, 9:00 p.m., Noyce Elbow. Nerf at Noyce.
  • Saturday, 29 March 2025, 4:00 p.m.–6:00 p.m., Aux Gym. Badminton Club (Smash that bird!)
  • Tuesday, 1 April 2025, Anywhere, Anytime. Conduct and reflect on a non-harmful April Fool’s Day prank.
  • Tuesday, 1 April 2025, 12:15–12:50 p.m., GCMoA. Yoga in the Museum.
  • Tuesday, 1 April 2025, 4:30–6:30 p.m., BRAC P103 (Multipurpose Dance Studio). Wellness Yoga.
  • Tuesday, 1 April 2025, 5:00–6:00 p.m., HSSC Atrium. Therapy Dogs.
  • Tuesday, 1 April 2025, 7:15–8:15 p.m., HSSC Atrium. Therapy Dogs.

Misc

  • Sunday, 30 March 2025, 7:30–8:30 p.m., Science 3819. Mentor Session
  • Tuesday, 1 April 2025, 7:00–8:00 p.m., Science 3820. Mentor Session
  • Wednesday, 2 April 2025, Noon–1:00 p.m., HSSC A2231 (Auditorium) Community Forum
    • “Weekly discussion on legal protections and recourse on issues that higher education and Grinnell College face.”

Other good things

These do not earn tokens, but are worth your consideration.

Upcoming work

Friday PSA

  • If you decide to consume substances that alter your body chemistry, please do so in moderation.
  • Make sure to do things other than homework. For example, walk in the sun or rain.
  • Consent is essential, but not sufficient.

Mini-Project 6

  • Two topics, both recursive.
  • The first topic is newly written. The second is newly edited.

Questions

MP6

Can we modify freestyles we’ve done on other project?

Yes.

Administrative

Other

Notes on Wednesday’s quiz

See recording or your notes (or both). (Or your memory.)

Notes on recent labs

From Monday’s lab: Why trace?

  • We have you study tracing, in part, so that you can start figuring out what these more complex procedures do.
  • Once you have mastered tracing, you can skip steps. Until then, you shouldn’t.

From Monday’s lab: What do the procedures do? (TPS)

func1a

;;; (func-1a x lst) -> list?
;;;   x : any?
;;;   lst : list?
;;; Add `x` to the end of `lst`.
(define func-1a
  (lambda (x lst)
    (if (null? lst)
        (list x)
        (cons (car lst) (func-1a x (cdr lst))))))

func1b

;;; (func-1b lst1 lst2) -> list?
;;;   lst1 : list?
;;;   lst2 : list?
;;; Adds `lst2` to the end of `lst1`.
;;; This is one way to implement `append`.
(define func-1b
  (lambda (lst1 lst2)
    (if (null? lst1)
        lst2
        (cons (car lst1) (func-1b (cdr lst1) lst2)))))

func2a

;;; (func-2a x lst) -> list?
;;;   x : any?
;;;   lst : list?
;;; Remove all copies of `x` from `lst`.
(define func-2a
  (lambda (x lst)
    (if (null? lst)
        null
        (if (equal? (car lst) x)
            (func-2a x (cdr lst))
            (cons (car lst) (func-2a x (cdr lst)))))))
    (func-2a 2 '(1 2 3 4))
    ; lst is not null, car lst is not 2
--> (cons 1 (func-2a 2 '(2 3 4)))
    ; lst is not null, car lst IS 2
--> (cons 1 (func-2a 2 '(3 4)))
    ; lst is not null, car lst is not 2
--> (cons 1 (cons 3 (func-2a 2 '(4))))
    ; lst is not null, car lst is not 2
--> (cons 1 (cons 3 (cons 4 (func-2a 2 '()))))
    ; lst IS null
--> (cons 1 (cons 3 (cons 4 '())))
--> (cons 1 (cons 3 '(4)))
--> (cons 1 '(3 4))
--> '(1 3 4))
(check-equal? "traced" (func-2a 2 '(1 2 3 4)) '(1 3 4))
(check-equal? "multiple 2's" (func-2a 2 '(1 2 2 3 2 4)) '(1 3 4))
(check-equal? "all x's" (func-2a "ex" (make-list 20 "ex")) '())
(check-equal? "big numbers; x is first" 
              (func-2a 5000 '(5000 5002 5003 5004))
              '(5002 5003 5004))
(check-equal? "nested lists, match at end"
              (func-2a '(a) '((y) (u) (c) (a)))
              '((y) (u) (c)))

func2b

; reverse `lst2` and shove it at the front of `lst1`.
(define func-2b
  (lambda (lst1 lst2)
    (if (null? lst2)
        lst1
        (func-2b (cons (car lst2) lst1) (cdr lst2)))))

r

(define r
  (lambda (lst)
    (func-2b '() lst)))

From Wednesday’s lab: How you’re supposed to approach problems

  • Document first. Documentation ensures, at minimum, that you’ve thought about input and output types.
  • Tests next. (Or write tests.) Your tests ensure that you’ve thought about a few cases. You’re going to “test” (experiment with your code) in any case, so why not spend the extra 30 seconds to write down your expectations?
  • Implement last. This may seem strange. Nonetheless, we’re best off waiting to implement until we’ve considered the issues above.

From Wednesday’s lab: Testing (TPS)

Tests for tally-odd

Tests for alphabetically-first?

From Wednesday’s lab: Alphabetically first (TPS)

At least four versions. We’re going to explore them a bit. But first, some documentation and tests.

;;; (alphabetically-first words) -> string?
;;;   words : list-of string?
;;; Find the alphabetically first string in `words`, using
;;; string-ci<=? for comparison.

What about our tests? (TPS)

Okay, on to our first version.

(define alphabetically-first-a
  (lambda (lst)
    (if (= 1 (len lst))
        (car lst)
        (if (string-ci<=? (car lst) (alphabetically-first-a (cdr lst)))
            (car lst)
            (alphabetically-first-a (cdr lst))))))

Hmmm … Sam says that when we repeat code, we should use a let binding. What’s repeated here?

(define alphabetically-first-b

Hmmm … Sam said something about how to check for one-element lists. How do we update that code.

(define alphabetically-first-c

Does it make a difference? We’ll start by defining a variety of values.

(define nums10 (map number->string (range 10)))
(define nums20 (map number->string (range 20)))
(define rev20 (reverse nums20))
(define nums22 (map number->string (range 22)))
(define rev22 (reverse nums22))
(define nums25 (map number->string (range 25)))
(define rev25 (reverse nums25))
(define nums30 (map number->string (range 30)))
(define rev30 (reverse nums30))
(define nums100 (map number->string (range 100)))
(define nums1000 (map number->string (range 1000)))
(define nums10000 (map number->string (range 10000)))
(define nums20000 (map number->string (range 20000)))
(define nums40000 (map number->string (range 40000)))

And some experiments with those. First we’ll look at version a.

Let’s compare version b.

And on to version c

Here’s another approach.

(define alphabetically-first-d
  (lambda (lst)
    (if (= 1 (len lst))
        (car lst)
        (if (string-ci<=? (car lst) (cadr lst))
            (alphabetically-first-d (cons (car lst) (cddr lst)))
            (alphabetically-first-d (cdr lst))))))

And here’s that same approach with a more sensible “does it have one item?”

(define alphabetically-first-e
  (lambda (lst)
    (if (null? (cdr lst))
        (car lst)
        (if (string-ci<=? (car lst) (cadr lst))
            (alphabetically-first-e (cons (car lst) (cddr lst)))
            (alphabetically-first-e (cdr lst))))))

And yes, it makes a difference.

> (time (alphabetically-first-d nums10000))
???
> (time (alphabetically-first-d nums40000))
???
> (time (alphabetically-first-e nums40000))
???

Here’s another approach, one based on largest.

(define largest
  (lambda (numbers)
    (if (null? (cdr numbers))
        (car numbers)
        (max (car numbers) (largest (cdr numbers))))))

(define alphabetically-first-f
  (lambda (words)
    (if (null? (cdr words))
        (car words)
        (alphabetically-first-of-two (car words)
                                     (alphabetically-first-f (cdr words))))))

(define alphabetically-first-of-two
  (lambda (str1 str2)
    (if (string-ci<=? str1 str2)
        str1
        str2)))
(define alphabetically-first-g
  (lambda (words)
    (afg-helper (car words) (cdr words))))

(define afg-helper
  (lambda (word remaining)
    (if (null? remaining)
        word
        (afg-helper (alphabetically-first-of-two word (car remaining))
                    (cdr remaining)))))

TPS: Which do you prefer (c, e, f, or g)? Why?

A few problems

We’ll also do these as TPS.

I’ll ask for documentation, then tests, then code.

grab

Like take, but still works if we try to grab more elements than there are. (in that case, it just returns what’s there).

skip

Like drop, but still works if we try to skip more elements than there are.

(merge-alternating lst1 lst2)

Alternately grab elements from the two lists, which may have different lengths. When we run out of one, grab from the other.