Skip to main content

CSC 151 2019S, Class 20: Recursion basics

Overview

  • Preliminaries
    • Notes and news
    • Upcoming work
    • Extra credit
    • Questions
  • Background
  • Key ideas in recursion
  • Sample recursive procedures
  • Expressing recursion in Scheme

Preliminaries

News / Etc.

  • Mentor sessions Wednesday 8-9 p.m., Thursday 8-9 p.m., Sunday 5-6 p.m.
  • We are starting on recursion this week and will continue after break. Recursion is a powerful technique, but sometimes a bit confusing at first. (Hey, you mastered regular expressions; you can master anything.)

Upcoming work

  • Reading for Wednesday: Recursion basics.
  • Exam 2 due Tuesday.
    • Do not discuss the exam (except with me)
    • Epilogue due Wednesday
    • Cover sheets also due Wednesday
  • No flashcards this week!
  • No lab writeup!
  • Quiz Friday: Match first names and faces. Those with multiple names will likely see both names appear.
    • If you won’t be in class on Friday, talk to me about when you might take the quiz.

Extra Credit

I would certainly appreciate suggestions of other extra credit activities (preferably via email).

Extra credit (Academic/Artistic)

  • CS Table, Tuesday, noon: Unknown topic
  • Convocation, Thursday at 11 in JRC 101

Extra credit (Peer)

  • Grinnell Singers, St. Paul Saturday, Rochester Sunday, …
  • Women’s Golf, Amelia Island, last Sunday of spring break.
  • Track and Field, Emory University, last weekend of spring break.

Extra credit (Wellness)

  • Sub-free spring break

Extra credit (Wellness, Regular)

  • 30 Minutes of Mindfulness at SHACS every Monday 4:15-4:45
  • Any organized exercise. (See previous eboards for a list.)
  • 60 minutes of some solitary self-care activities that are unrelated to academics or work. Your email reflection must explain how the activity contributed to your wellness.
  • 60 minutes of some shared self-care activity with friends. Your email reflection must explain how the activity contributed to your wellness.

Extra credit (Misc)

Other good things

Questions

If you miss a quiz, what grade do you get?

Zero

Is the lowest quiz grade dropped?

Yes

So if you miss one quiz, it gets dropped?

In effect, yes.

Do you exempt people with facial recognition issues from Friday’s quiz?

Yes. Provided it is documented with academic advising.

I have random problems running loudhum on my computer.

Let’s talk offline.

Can we ask you broad questions on the exam?

Yes.

In the tweet problem, what should we do about things that have values that are numbers or true or false?

You need not support them.

What should our samples look like for the last problem?

(post->xml (post "Sample one" "Foo" "Bar" (list) 100)) (post->xml (post "Sample two" "Qux" "Quux" (list "A" "B" "C") 23)) (post->xml (post "Sample three" "Qux" "Quux" (make-list 100 "Charred") 123123123124512321)) (xml->post '(post (title "T") (author "A") (content "C") (tags (tag "T")) (views "-5")))

Can you give an example in which you might want multiple consequents?

(define silly
  (lambda (val)
    (cond
      [(list? val)
       (for-each (lambda (x) (hash-set! hash x (string-upcase x))) val)
       val]
     ...)))

That is, for-each returns void. Perhaps I want something other than void back, such as my original input.

Background

At the beginning of the semester, we learned about various parts of algorithms, including the following

  • Conditionals
  • Variables (identifiers, named values)
  • Repetition
  • Input/Output
  • Built-in Functions
  • Sequencing
  • Subroutines

And we’ve learned how to write them in Scheme/Racket.

Variables

  • (define name value)
  • (let ([name value]) ...)

Conditionals

  • (if (condition) true-thing false-thing)
  • (cond [(guard) consequent consequent] [(guard) consequent] ... [else alternate])
  • (when (condition) consequent1 consequent2 consequent3)

Note:

  • Use cond or when when you want multiple consequents.
  • Use if or when when you only need one test.
  • Use when when you don’t have an alternate.

Repetition

  • (for-each proc lst) - does the same procedure again and again on different values.
  • (map proc lst) - does the same procedure again and again on different values, accumulating the results into a new list.
  • (reduce binproc lst) - Repeatedly apply binproc to neighboring pairs until the values are reduced to a single value.
  • (filter pred lst) - Test each element of the list, returning a list containing only those that match.

Input/Output

  • Input: We can type expressions, DrRacket evalutes them, and prints the result
  • We’ve also seen display (briefly)
  • We can also read from files and write to files. (file->string, string->file, etc.)

Built-in Functions and Types

  • (make-string n char) - Makes a string with n copies of char. (Can be helpful with repetition.)
  • (make-list n thing) - Makes a list (Can be helpful with repetition)
  • Strings - list->string, string-append, string-ref, string-trim, substring, string-length, string?, all of the wonderfully helpful regexp procedures, string-split, string->number, number->string, string-ci<?
  • Lists
  • Characters
  • Numbers
  • Hash tables
  • Structs
  • XML

Sequencing

  • You can’t use things before they are defined.
  • Racket generally works inside-out on complex expressions. (nesting)
  • Composition: (o proc2 proc1) Do proc1 then proc2.
  • let*, evaluates its values one at a time.
  • Multiple consequents in a conditional get evaluated one after another
  • If you write multiple expressions on separate lines, they get evaluated one at a time.
  • In the body of a let or lambda, if there are multiple expressions, they get evaluated one at a time, with the value of the last one being used as the result.
  • cond sequences tests.

Subroutines

  • (lambda (params) body).
  • (section proc param <>)
  • (o proc2 proc1).
  • We can name them with define and let.

Questions

What is the role of husk and kernel?

It’s a program design strategy; it is not strictly necessary for writing algorithms.

Or maybe a use of conditionals.

Key ideas in recursion

Recursion is a general technique for repeating actions.

Recursion involves delegation, of sorts

  • To solve a problem, you ask an assistant (a helper function) to solve a simpler version of the problem and use that solution to solve your overall problem.
  • Some problems are simple enough that you can solve them directly.
  • Weird idea: The helper function can be the same algorithm as the main function.

Sample recursive procedures

How many of these words have two consecutive identical letters?

  • If there are no words, return 0
  • Remove one card
  • Ask you assistant how many have two consecutive identical letters
  • Look at your card. If it has two consecutive identical letters, add 1 to that number. Otherwise, just give back that number.

Which words have two consecutive identical letters?

  • If there are no words, return the empty list
  • Remove one card
  • Ask you assistant to do the same task
  • Look at your card. If it has two consecutive identical letters, add it to the list you received from your assistant and pass it on. Just pass along the list the list you got from your assistant number. Otherwise, just give back that number.

Expressing recursion in Scheme

Turn the following into Racket.

  • If there are no numbers, return 0
  • Call a helper procedure that counts how many odd elements there are in the remainder of the list. (All but the first element.)
  • Look at the first number. If it’s odd, add 1 to the previous number.
  • Otherwise, just return the previus number.
;;; Procedure:
;;;   tally-odd?
;;; Parameters:
;;;   nums, a list of integers
;;; Purpose:
;;;   Count how many odd numbers are in the list.
;;; Produces:
;;;   count, a count of the odd numbers
(define tally-odd?
  (lambda (nums)
    (if (null? nums)
        0
        (+ (if (odd? (car nums)) 1 0)
           (tally-odd? (cdr nums))))))
(tally-odd? '(2 3 1 4 5))
=> (+ (if (odd? 2) 1 0) (tally-odd? '(3 1 4 5)))
=> (+ 0 (tally-odd? '(3 1 4 5)))
=> (+ 0 (+ (if (odd? 3) 1 0) (tally-odd? '(1 4 5))))
=> (+ 0 (+ 1 (tally-odd? '(1 4 5))))
=> (+ 0 (+ 1 (+ (if (odd? 1) 1 0) (tally-odd? '(4 5)))))
=> (+ 0 (+ 1 (+ 1 (tally-odd? '(4 5)))))
=> (+ 0 (+ 1 (+ 1 (+ (if (odd? 4) 1 0) (tally-odd? '(5))))))
=> (+ 0 (+ 1 (+ 1 (+ 0 (tally-odd? '(5))))))
=> (+ 0 (+ 1 (+ 1 (+ 0 (+ (if (odd? 5) 1 0) (tally-odd? '()))))))
=> (+ 0 (+ 1 (+ 1 (+ 0 (+ 1 (tally-odd? '()))))))
=> (+ 0 (+ 1 (+ 1 (+ 0 (+ 1 0)))))
=> (+ 0 (+ 1 (+ 1 (+ 0 1))))
=> (+ 0 (+ 1 (+ 1 1)))
=> (+ 0 (+ 1 2))
=> (+ 0 3)
=> 3

Key ideas:

  • Use the same procedure as a helper.
  • This builds up a lot of delayed evaluation.

Why would we use recursion instead of filter or tally?

  • We used recursion to write filter and tally (and reduce).
  • We use recursion to define range.
  • If we wanted to process an XML tree in a new way, we might want to recurse over that tree (coming after break).
  • Any time we want to do repetition that does not fit into the neat little boundaries of the things we’ve learned.
  • (string-range str1 str2) generates all strings that come between str1 and str2. (string-range "a" "f") -> ‘(“a” “b” “c” “d” “e” “f”)`.
  • Maybe to simulate calculus.

How about filtering?

(define filter-odd
  (lambda (nums)
    (if (null? nums)
        null
        (if (odd? (car nums))
            (cons (car nums)
                  (filter-odd (cdr nums)))
            (filter-odd (cdr nums))))))
(filter-odd '(5 2 1 4 3))               ; not null, car is odd
=> (cons 5 (filter-odd '(2 1 4 3)))     ; not null, car is not odd
=> (cons 5 (filter-odd '(1 4 3)))       ; not null, car is odd
=> (cons 5 (cons 1 (filter-odd '(4 3))))       ; not null, car is not odd
=> (cons 5 (cons 1 (filter-odd '(3))))  ; not null, car is odd
=> (cons 5 (cons 1 (cons 3 (filter-odd '())))) ; null
=> (cons 5 (cons 1 (cons 3 '())))
=> (cons 5 (cons 1 '(3)))
=> (cons 5 '(1 3))
=> '(5 1 3))

As I noted, we build up a lot of delayed work while waiting for the recursive calls to finish. (It’s a bit like waiting for the verb in German.)

How do you get the second element in a list?

> (list-ref lst 1)
> (car (cdr lst))
> (cadr lst) ; (car (cdr lst))