EBoard 27: SoLA Three

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 [~5 min]
  • Q&A [up to 90 min or so]

Administrative stuff

Notes and news

  • It’s SoLA 3 day!
  • Today’s class is optional. I will be here to answer any outstanding questions you might have.

Tutoring reminders

  • Please don’t ask tutors questions on LAs.
  • Please use our tutors! They like to work.
  • 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.
    • We should have two evening tutors on Wednesdays.
    • Don’t forget to cite the evening tutors (and the individual tutors).

Upcoming activities

Attend (or watch recording within a day or so) and send a one-paragraph reflection asap afterwards.

Only those activities I list count.

  • Tonight’s Writers at Grinnell.
  • Noon, Wednesday, 9 December 2020: Community Convesation
  • 5:00 p.m. Thursday, 10 December 2020: MIST: The Mathematical Image Synthesis Toolkit. Sam’s research students. (+2 tokens, even if you critique their work)
  • Friday, 2:00 p.m., Newberry Library Session

Upcoming work

Mini Projects

Readings

  • Reading for Wednesday

Quizzes

  • No quiz today
  • Quiz Wednesday: Hash Tables and Dictionaries

Other

  • SoLA 3 TODAY (no quiz)

Q&A

I’m going to take a bunch of questions at first, answer the short ones, and put the long ones on hold. Then I’ll answer the long ones and we’ll do it all over again.

I forgot to ask for more time on my SoLAs before the deadline. Can I still get more time?

Yes. You can ask out loud now or just chat me in Teams. 30, 40, 50, or 60.

I have an accommodation that gives me a particular extension on the SoLAs. Can I ask for more than that on the SoLAs.

Of course. Just let me know how long you want.

Will you go over vector-swap-neighbors!?

Sure

Vectors

Write a procedure, (vector-swap-neighbors! vec) that takes an even-length vector as a parameter and swaps the neighboring elements (those at indices 0 and 1, those at indices 2 and 3, etc.).

(define vector-swap-neighbors!
  (lambda (vec)
    (let ([len (vector-length vec)])
      (letrec ([helper
                (lambda (pos)
                  (when (< pos len)
                    (let ([val0 (vector-ref vec pos)]
                          [val1 (vector-ref vec (+ 1 pos))])
                      (vector-set! vec (+ pos 1) val0)
                      (vector-set! vec pos val1)
                      (helper (+ pos 2)))))])
        (helper 0)))))
> (define vec2 (vector 'a 'b 'c 'd))
> (vector-swap-neighbors! vec2)
> vec2
'#(b a d c)
> (define vec3 (list->vector (range 20)))
> vec3
'#(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
> (vector-swap-neighbors! vec3)
> vec3
'#(1 0 3 2 5 4 7 6 9 8 11 10 13 12 15 14 17 16 19 18)

Here’s a trace of an earlier incorrect version.

;     (vector-swap-neighbors! (vector 'a 'b 'c 'd))
; --> (helper 0)
; --> ; val0 'a val1 'b
; --> ; vector is now (vector 'b 'a 'c 'd)
; --> (helper 2)
; --> ; val0 is 'b

When should we use when?

When writing recursive procedures in a world with side effects, we often need to sequence operations (do this, then this, then recurse).

if doesn’t give us multiple consequents or multiple alternates.

We have a few choices. We could use cond

    (cond
      [(< pos len)
       (vector-set! vec (+ pos 1) val0)
       (vector-set! vec pos val1)
       (helper (+ pos 2))]
      [else
       vec])

But I don’t like to return vectors from ! procedures.

So I guess I could write

    (cond
      [(< pos len)
       (vector-set! vec (+ pos 1) val0)
       (vector-set! vec pos val1)
       (helper (+ pos 2))])

when is just a shorter version of the cond I just wrote. It saved me two whole square brackets. But I find them easier to read.

If the guard in the when does not hold, the when does nothing and has no value (void).

Don’t use when if you want an alternate. Use cond. Feel free to skip when altogether.

Could you discuss the mechanics of the vector recursion?

Sure.

In most vector-recursive procedures, we want to step through the indices. From 0 up to the last index. Or from the last index down to 0.

From 0 up is the most common.

Essentially, we’re doing numeric recursion with vector indices from 0 up to (- (vector-length vec) 1).

pos is the term I use for the index. “position”.

If we’re counting up from 0, we want to initialize the recursive process at zero.

(let ([helper 
       (lambda (pos) 
         ...)]) 
  (helper 0))

Mental Models of Memory

Describe or diagram the layout of memory for lists and vectors/arrays.

Consider the following pair structure represented in ASCII art.

(cons "a"  (cons *    (cons "e"  (cons "f" null))))
+---+---+  +---+---+  +---+---+  +---+---+
| * | *--->| * | *--->| * | *--->| * | / | 
+-|-+---+  +-|-+---+  +-|-+---+  +-|-+---+
  v          |          v          v
 "a"         |         "e"        "f"
             v
           (cons *    (cons null (cons * null)
           +---+---+  +---+---+  +---+---+
           | * | *--->| / | *--->| * | / | 
           +-|-+---+  +---+---+  + | +---+
             v                     v
           (cons * null)         (cons "c" "d")
           +---+---+             +---+---+
           | * | / |             | * | * | 
           +-|-+---+             +-|-+-|-+
             v                     v   v
           (cons null "b")        "c" "d"
           +---+---+                      
           | / | | | 
           +---+-|-+
                 v
                "b"
(cons "a" 
      (cons '...
            (cons "e"
                  (cons "f"
                        null))))
(cons "a" 
      (cons (cons (cons (cons null "b")
                        null)
                  (cons null
                        (cons (cons "c" "d")
                              null)))
            (cons "e"
                  (cons "f"
                        null))))

Wasn’t that fun?

'("a" ("b" "c" . "d") () (("e")))
(cons "a" 
      (cons (cons "b"
                  (cons "c"
                        "d"))
            (cons null
                  (cons (cons (cons "e"
                                    null)
                              null)
                        null))))
+---+---+   +---+---+   +---+---+   +---+---+
| * | *---> | * | *---> | / | *---> | * | / |
+-|-+---+   +-|-+---+   +---+---+   +-|-+---+
  v           v                       v
 "a"

Can we review hops?

hops = higher-order procedures

(define silly
  (lambda (lst)
    (map (lambda (x) (sqr (+ 1 x)))
         (filter odd? lst))))

Strategies

  • One goal of hops is to take a step back and rethink what I’m doing and in what order.
  • Section: Taking a multi-parameter procedure and making it a fewer-parameter procedure (usually going from many to one).
  • Compose: Do this, then do this, then do this.
  • Sometimes this lets us restructure procedures (for clarity, elegance, avoiding naming helpers we only use once)

Let’s consider the inner lambda first.

  • (lambda (x) (sqr (+ 1 x)))
  • First I’m adding one to x, then I’m squaring the result
  • I’ll probably write a composition (o sqr "add one to")
  • What is “add one to”? A procedure that adds one to its parameter.
  • Filling in one parameter to + is an instance of section.
  • (o sqr (section + 1 <>))
(define sillier
  (lambda (lst)
    (map (o sqr (section + 1 <>))
         (filter odd? lst))))

Let’s deal with outer lambda.

  • Start with a list.
  • Filter out some elements
  • Map something over that list.
  • That’s a composition. We’re doing two things in sequence.
  • (o map-thingy filter-thingy)
  • The filter thingy is (section filter odd? <>)
  • The map thingy is mapping some ugly thing over a list, so it’s (section map ugly-thing <>)
  • That is (section map (o sqr (section + 1 <>)) <>)
(define silliest
  (o (section map (o sqr (section + 1 <>)) <>)
     (section filter odd? <>)))

The diamonds represent “the input to this procedure”. (That’s one of the reasons we often go to a one-parameter procedure; it’s easier to think of just one input than many.)

Mini-Project Headers

Similar to the lab headers.

;; CSC 151.02 (Fall 2020, Term 2)
;; Mini-Project 5
;; Authors: YOUR NAMES HERE
;; Date: THE DATE HERE
;; Acknowledgements:
;;   ACKNOWLEDGEMENTS HERE

Citations

At the top.

;; Acknowledgements:
;;   * Sam helped on the broad design of the project.
;;   * L's questions in class gave me a sense of how to approach
;;     the question on haiku.
;;   * Mai helped correct my code on the haiku.
;;   * I referred to the Racket page on `andmap` at 
;;     <https://docs.racket-lang.org/reference/pairs.html>

In the documentation for procedures.

;;; (haiku) -> string?
;;;
;;; I found starter code on Stack Overflow at <...>.
;;; Mai helped me correct some of the problems.

I’m happy with either, with a slight preference for both.