EBoard 18: Recursion

This class will be recorded! Its use is limited to members of the class. Please do not share with others.

Approximate overview

  • General administrative stuff [~10 min]
  • Q&A [~10 min]
  • Quiz [~10 min]
  • Testing [~10 min]
  • Lab [~50 min]

Administrative stuff

Notes and news

  • Let’s hope we have lots of lab time today! But we will see.
  • I had Interweb problems over the weekend, I remain behind. It didn’t help that I also had to start dealing with Cut/Close/Balance issues. (First years will learn about those.)
    • Warning! We may be (probably temporarily) cutting some of you from 207.
  • Congratulations! You’ve made it through half the class periods of CSC-151. (I can’t really say that you’re halfway through class since the SoLAs are a bit back-weighted.)
  • Sample LAs posted.
  • Review sessions at 5pm and 9pm tonight. (+1 token)
  • You need not attend class tomorrow. I will show up to answer pre-SoLA questions.
  • If you want extra time on SoLA 2, let me know by 10 p.m. tonight.
  • The Testing quiz did not go well, so we’re talking about testing today.
  • I’m revising the token policies
    • Quiz makeups are free for those who take the quiz on time.
    • Quiz makeups cost a token for those who don’t take the quiz.
    • Mini-project makeups are free for those who turn them in on time.
    • Late mini-projects cost a token.
    • Makeups for late mini-projects cost a token.
    • Lab and reading makeups are free for those who turn them in on time. (These makeups get handled by direct negotiation with SamR.)
    • It costs a token to turn these in late.
    • Redos are not allowed for late labs/readings.

Tutoring reminders

  • Please use our tutors! They like to work.
    • Don’t use them for help on the quizzes or learning assessments.
  • Evening tutoring will be available
    • 8-10 p.m. Sundays through Thursdays
    • 3-5 p.m. Sundays
    • In the “Drop in tutoring” channel on the CS team.
    • Sam will generally not be available during these times.
  • Individual tutors are temporarily unavailable. We’re recruiting more.

Upcoming activities

Attend (or watch recording) and send a one-paragraph reflection.

  • Noon, TODAY, CS Table.

Upcoming work

  • SoLA2: Tomorrow!
  • Redo of Mini-project 2 (due Monday the 30th at 10:30 p.m. CST)
  • Redo of Mini-project 3 (due Monday the 30th at 10:30 p.m. CST)
  • Mini-project 4 (due December 2 at 10:30 p.m. CST)
  • No reading for tomorrow.
  • Reading for Wednesday
  • Quiz Wednesday: Recursive templates and matching.

Q&A

Will we get cut from 161?

Nope.

Do we have to retake quizzes we got points for?

No.

The add-to-end and append-lists procedures from the last lab seemed like a lot of work to do a simple thing. Is there a better way?

In terms of the underlying list model in Scheme: No.

In terms of what you have to write: Yes. (reverse (cons x (reverse l)))

To deal with the end of the list, you have to recurse through the list.

I was using an if for the self-check. What are other options?

Lab.

Pattern Matching

Could you explain pattern matching?

There are situations in which you would probably write a cond and each aspect of the cond would depend on the structure of some value.

(define add-to-end
  (lambda (lst val)
    (cond
      [(null? lst)
       (list val)]
      [(not (list? lst))
       (error "That's not a list")]
      [else
       (cons (car lst) (add-to-end (cdr lst) val))])))

When our cond is basically structural, we can use match instead.

(define add-to-end
   (lambda (lst val)
     (match lst
       ['() 
        (list val)]
       [(cons x xs)
        (cons x
              (add-to-end xs val))]
       [something-else
        (error "Not a list")])))

The other nice thing about match is that it allows us to name the parts of something. (See the x and xs above.)

Intuition

“A piecewise function”

  • Factorial(0) = 1
  • Factorial(n) = n * Factorial(n-1)
> (define !
    (lambda (n)
      (match n
        [0 1]
        [other (* n (! (- n 1)))])))

> (! 0)
1
> (! 6)
720

I get the meaning but not the syntax.

Practice.

Quiz

  • You may want to open the first reading and lab on recursion.
  • You will be reading or commenting on recursive procedures, not writing recursive procedures.
  • You might want to bring up DrRacket.

On testing

Some notes

  • Good testing should feel a lot like the experimenting you normally do in the interactions pane. I type “this input” and look for “this output”. We’ve just told the computer to do it for us and added a note as to why.
    • “I’m going to type (foo (bar 3)); I expect to see 42.”
    • (check-equal? (foo (bar 3)) 42 "Life, the Universe, and Everything")
    • “I’m going to type (sublist '(A B C D) 2 4); I expect to see '(B C).”
    • (check-equal? (sublist '(A B C D) 2 4) '(B C) "Middle of four-element list")
  • Our goal is to give enough variety of input that we can be confident that the procedure works correctly.
  • Almost all tests are “If I give the procedure these correct inputs I should get These outputs.”
    • Tests are for things that should happen.
    • Tests are not “Watch it crash when I give it bad inputs.*
  • We also look for “edge cases”, at the boundaries of what valid inputs can be. (Empty lists. Large numbers. Limits of legal values on inputs.)
  • I tend to make it a habit to do slightly more complex testing; you need not.
  • Two somewhat conflicting approaches
    • Put all the tests into a big test suite.
    • Just put check-equals? (or whatever) tests immediately below the procedure definition.
  • I find the latter appropriate because it’s faster.
  • And your development cycle should be: Document, Write Tests, Write Code

The previous quiz

Consider the following (unimplemented) procedure.

  ;;; (sublist lst start finish) -> list-of any?
  ;;;   lst : list-of any?
  ;;;   start : integer?
  ;;;   finish : integer?
  ;;; Grab the sublist of lst starting at start and finishing
  ;;; immediately before finish.
  ;;;
  ;;; Prereq: 0 <= start <= finish <= (length lst)

Write five or more tests of sublist, including at least two “normal cases” and at least two “edge cases” or “corner cases”.

Use the simple check-equal? format.

The syntax is (check-equal? expression expected note). It’s fine if you don’t get it quite right. ```

One example

(check-equal? (sublist (list "A" "B" "C") 1 2)
              (list "B")
              "Single element of a list of strings")

Things Sam saw

  • People putting in inputs that would break sublist
  • Not a lot of variety; variety is good
  • Failure to think about edge cases

Your goal. Come up with one “normal” case and one “edge” case that you think will be (a) useful and (b) different than what others are posting. I will likely call on you.

(check-equal? (sublist (map thing (list "red" "yellow" "green" "blue" "purple")) 4 5)
              (list (thing "purple"))
              "Shapes, end of list")

(check-equal? (sublist (list #\a #\b 0.5 3.0) 0 1)
              '(#\a)
              "Multiple types, looking at the start of the list")
(check-equal? (sublist (list 1 2 3 7 5 43 4 5) 1 3)
              '(2 3)
              "Normal case 1")
(check-equal? (sublist (list 0 0 0 0 0) 0 1)
              '(0)
              "Start of list; zeros mess stuff up")
(check-equal? (sublist '(8 7 5 4) 2 3)
              '(5)
              "Normal case, looking for single element")
(check-equal? (sublist '(8 7 5 4) 2 2)
              '()
              "Empty list, taken from the middle")
(check-equal? (sublist (list "a" "b" "c") 0 0)
              '()
              "start and finish are the same")
(check-equal? (sublist '() 0 0)
              '()
              "starting with the empty list")
(check-equal? (sublist (range 20) 0 20)
              (range 20)
              "Whole list for a large list")

How many tests should we write?

It depends on the situation.

Enough that you would stake your grade (on the assignment?) on the correctness of the procedure.

As many as Sam says.

Lab

You should know the drill by now.

You will just access the .rkt files directly today (at least I hope you will).