---
title: Eboard 23  Discuss exam 2
number: 23
section: eboards
held: 2019-04-01
link: true
---
CSC 151 2019S, Class 23:  Discuss exam 2
========================================

_Overview_

* Preliminaries
    * Notes and news
    * Upcoming work
    * Extra credit
    * Questions
* Common problems
* Improving style
* Questions
* Notes on recursion

Preliminaries
-------------

### News / Etc.

* Welcome back from break!  And happy April Fool's day!
    * My CSC 207 exams took approximately twice as long to grade
      as I had anticipated, so I am still behind on everything.
* Sit alphabetically today (cards are at workstations to
  help you figure out where to sit)
* Mentor sessions Wednesday 8-9 p.m., Thursday 8-9 p.m., Sunday 5-6 p.m.
* Exam 2 returned via email.  Notes also distributed via email.
* Quizzes returned
* Do you want the traditional "Sam wears a costume on April Fools' Day" jokes?

### Upcoming work

* Next homework to be assigned on Wednesday.  Topic: Recursion.
* Friday's quiz: Recursion
* Reading for Wednesday: See the schedule
* No lab writeup!
* No flash cards this week.

### Extra Credit

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

#### Extra credit (Academic/Artistic)

* Convo Thursday (sorry, I don't know details yet)
* Foreign service alum presentation: HSSC S3325, 7:30 tonight.
* Talk on future of agriculture, 4:15, somewhere in the Husk (HSSC).

#### Extra credit (Peer)

* Grinnell Singers, Sunday the 7th at ???
* Women's golf, Saturday/Sunday somewhere in St. Louis
* Track and Field, Saturday at Cornell

#### Extra credit (Wellness)

#### 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)

* Wednesday the 10 at 4pm on Mac Field: Giant Laurel Leaf.  (Free t-shirt!)
* Scarlet and Give Back Day next Wednesday/Thursday (I think).  If you
  don't have money to donate, let me know and I will give you $5 to donate.

### Other good things 

### Questions

_Not questions about the exam.  Those come later._

Common problems
---------------

* Too many of you did well.  (Not a problem, that's a good thing.)
* There are still some issues on postconditions.
* Some of you need to work on your style (a lot)
* At this point, you should be avoiding repetitious code using
  helper procedures or lets or ...
* Not anonymous
* Use YYYY-MM-DD

Some repetition
---------------

Example one

    (list-ref (list-ref thing1 0) 1)
    (list-ref (list-ref thing2 0) 1)
    (list-ref (list-ref thing3 0) 1)
    (list-ref (list-ref thing4 0) 1)
    (list-ref (list-ref thing5 0) 1)


    (define uh ; use helper
      (lambda (thing)
        (list-ref (list-ref thing 0) 1)))

    (uh thing1)
    (uh thing2)
    (uh thing3)
    (uh thing4)
    (uh thing5)

Note: "uh" is funny, but not a particularly good name.

    (regexp-match "<tag1>[^<]*</tag1>" (xml->string xml))
    (regexp-match "<tag2>[^<]*</tag2>" (xml->string xml))
    (regexp-match "<tag3>[^<]*</tag3>" (xml->string xml))
    (regexp-match "<tag4>[^<]*</tag4>" (xml->string xml))
    (regexp-match "<tag5>[^<]*</tag5>" (xml->string xml))

Let's write a helper procedure

    (define extract-tag
      (lambda (pattern xml)
        (regexp-match pattern (xml->string xml))))
    (extract-tag "<tag1>[^<]*</tag1>")
    (extract-tag "<tag2>[^<]*</tag2>")
    (extract-tag "<tag3>[^<]*</tag3>")
    (extract-tag "<tag4>[^<]*</tag4>")
    (extract-tag "<tag5>[^<]*</tag5>")

Here's a better version

    (define extract-tag
      (lambda (tag xml)
        (regexp-match (string-append "<" tag ">[^<]*</" tag ">")
                      (xml->string xml))))
    (extract-tag "tag1")
    (extract-tag "tag2")
    (extract-tag "tag3")
    (extract-tag "tag4")
    (extract-tag "tag5")

It probably works, but we might be able to do even better with a `map`
or `for-each`, e.g.,

    (map extract-tag (list "tag1" "tag2" "tag3" "tag4" "tag5"))

Note: We are calling `xml->string` five times.  It's an expensive procedure.
We should avoid that.

We could write a `let` statement instead.

    (define extract-tag
      (lambda (tag xmlstr)
        (regexp-match (string-append "<" tag ">[^<]*</" tag ">")
                      xmlstr)))
    (let ([xmlstr (xml->string xml)])
      (map (lambda (tag) (extract-tag tag xmlstr))
           (list "tag1" "tag2" "tag3" "tag4" "tag5")))

Same number of lines, but more general and more efficient.

Moral: To avoid repetition,

* Use helper procedures
* Use let
* Use map

Postconditions
--------------

Goal: To restate the purpose more formally, thereby avoiding ambiguity.

* Scheme and Math are good ways to avoid ambiguity.
* If I can write a procedure that meets your postconditions, but does not
  achieve the implicit goal, your postconditions don't suffice.
* "random-story generates a funny story".  "Sam, while wearing a Tigger
  costume, ate a winnie the pooh doll."

Postconditions for hash-invert

```drracket
;;; Procedure:
;;;   hash-invert
;;; Parameters:
;;;   hash, a hash table
;;; Purpose:
;;;   Invert the hash table
;;; Produces:
;;;   inverted, a hash table
;;; Preconditions:
;;;   [No additional]
;;;   For any two keys, k1, k2, (hash-ref hash k1) is not equal to
;;;     (hash-ref hash k2).  That is, keys can't have duplicate values.
;;; Postconditions (with some repetition):
;;;   * If hash is empty, inverted is also empty
;;;   * For all keys, k, in hash:
;;;     If (hash-ref hash k) = v, then (hash-ref inverted v) = k
;;;   * For all keys, k, in hash:
;;;     (hash-ref inverted (hash-ref hash k)) = k
;;;     [another way to say the previous postcondition]
```

Suppose `hash` is `#hash(("A" . "Apple") ("B" . "Banana"))`, what is
a hash table that meets the postconditions, but is not what you would
call an inverse of the original?

```drracket
#hash(("Carrot" . "C") ("Apple" . "A") ("Banana" . "B"))
```

How could we write a postcondition that addresses that issue?

```drracket
;;;   * The number of keys in `inverted` must be the same as the
;;;     number of keys in `hash`.  
;;;     (= (length (hash-keys inverted)) (length (hash-keys hash)))
```

How would you write the postconditions if we allowed two keys in
`hash` to have the same value?

```drracket
#hash(("Apple" . "A") ("Aardvark" . "A") ("Banana" . "B")))
```

What is the inverse of that table?

```drracket
#hash(("A" . "Apple") ("B" . "Banana"))
```
or 

```drracket
#hash(("A" . "Aardvark") ("B" . "Banana"))
```

```drracket
;;; Postconditions:
;;;   * If two or more keys in hash have the same value, then
;;;     inverted will have a pair with that value as its key
;;;     and one of those keys as its value. [Sam worries that this
;;;     is incomplete.]
;;;   * For all keys, k, in inverted:
;;;     (hash-ref keys (hash-ref inverted k)) = k
;;;   * If (hash-ref hash k) = v for some k, then v is a key of
;;;     inverted.
;;;   * inverted has no other keys.
```

Documenting `sort-by-length`

```
;;; Procedure:
;;;   sort-by-length
;;; Parameters:
;;;   strings, a list of strings [verified]
;;; Purpose:
;;;   Sort strings from shortest to longest; if two strings have
;;;   the same length, they should be in ASCII order.
;;; Produces:
;;;   sorted, a list
;;; Preconditions:
;;;   * strings must not be empty
;;; Postconditions:
;;;   * (= (length sorted) (length strings))
;;;   * If str2 appears immediately after str1 in sorted, then
;;;     Either (string-length str1) < (string-length str2)
;;;     Or the lengths are equal and (string-ci<=? str1 str2)
;;;   * The elements in sorted are the same as the elements in strings.
```

SamR's solution if we don't have the third precondition

```drracket
(define sort-by-length
  (lambda (strings)
    (make-list (length strings) "done")))
```

Note: We could replace the first and third postconditions with

```drracket
;;;   * sorted is a permutation of strings
````

Improving style
---------------

1. Lines should not be more than 80 characters.

```drracket
(string-append "once upon a time " (generate-something "hello" "gooodbye") " there was a " (generate-noun) " ... ")
```

2. Spaces or newlines belong between the parameters to a procedure.

```drracket
(string-append"hello"(generate)" and "(generate)) ; bad
(string-append "hello" (generate) " and " (generate)) ; good
(string-append "hello" 
               (generate) 
               " and " 
               (generate)) ; better 
```

3. Traditionally, either all parameters on one line, or each parameter
   on a separate line.  (There are a few cases in which things are 
   clearer if you put multiple parameters on one line.)

```drracket
(list-ref
 (list-ref
  (some complex expression that was very very long longer) 1) 0) ; BAD
```

4. Names should be descriptive.

5. Follow Racket indentation guidelines.  (Force Racket to reindent.)

Individual questions
--------------------

How do you verify that everything in a list is a string?

> `(all string? strings)`

Notes on recursion
------------------
