---
title: Eboard 20  Recursion basics
number: 20
section: eboards
held: 2019-03-11
link: true
---
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](../readings/recursion-basics).
* [Exam 2](../exams/exam02) 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?_

```drracket
(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.

```drracket
;;; 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))
```

