Skip to main content

CSC 151.01, Class 43: Higher-order procedures, continued

Overview

  • Preliminaries
    • Notes and news
    • Upcoming work
    • Extra credit
    • Questions
  • Quick review
  • Lab

News / Etc.

  • Maintain partners from yesterday.
  • Review sessions at 9:00 a.m., 7pm, and 8pm tomorrow.
    • 9:00 a.m. session ends early so that Sam can meet with the Dean
    • Evening sessions have snacks (fruit)

Upcoming Work

  • Lab writeup: Exercise 6.
  • Cover sheets due NOW. Make sure to sign and date each statement separately (assuming you can comfortably sign).
  • Reading for Monday: Files in Scheme
  • Exam 3 epilogue due TONIGHT.
  • Quiz Friday
  • Project Proposals due next Monday evening (sketches Tuesday).

Quiz topics

  • Trees
  • Higher-order procedures
  • Maybe randomness, depending on how unpredictable we are feeling
  • Maybe some related past stuff.

Extra credit (Academic/Artistic)

  • Any of the Research, Scholarship, and Creative Activity Symposium events April 17-20.
  • Quince Contemporary Vocal Ensemble. 7:30 p.m., Wednesday, April 19, Sebring-Lewis. http://www.quince-ensemble.com/about.
  • Scholars’ Convocation, Thursday, 11:00 a.m. Weiman on Hamilton versus Jackson: A Monetary Debate
    • Warning! This is the PBK convocation, so the first twenty minutes or so are students joining PBK. (You can applaud your peers!)
  • #robinhoodfail: The Ethics of Public Scholarship and the Digital Liberal Arts, Thursday, 7:30 pm, JRC 101.
  • Met Opera Live in HD: Eugene Onegin. Saturday, April 23. Opera Talk, 11:30 a.m., Opera, noon, Harris Center Cinema

Extra credit (Peer)

  • Any of the Research, Scholarship, and Creative Activity Symposium events that involve your classmates, April 17-20. (No double dipping!)
  • Vocal recitals with Prof. Miguel. Friday at 7:30 in Sebring-Lewis.
  • Art House Arts Fest on April 22nd.
  • ATP’s play (sold out)
  • ISO Cultural Evening, Saturday, 7-9, Harris Concert Hall
  • Vietnamese Food Stall, 6-8, Friday, JRC 2nd

Extra credit (Misc)

None right now.

Other good things to do

  • If you participate in Thursday’s 20/4 festivities, be moderate.
  • Dag Field Day, Saturday, April 29, noon-5pm, in the Club Athletic Field.

Notes on 2b (or not)

The problem

a. Here are four expressions to generate the successors of the squares of the first ten positive integers. Verify that each works correctly.

(define v1 (map increment (map square (map increment (iota 10)))))
(define v2 (map (lambda (i) (increment (square (increment i)))) (iota 10)))
(define v3 (map (compose increment (compose square increment)) (iota 10)))
(define v4 (map (o increment square increment) (iota 10)))

b. Which of the four definitions above you prefer? Why? Be prepared to discuss your reasons with the class.

Part one

Thirty seconds with your partner. Suppose you were choosing between these definitions. Which would you choose? Why?

> (let ([fun (lambda (x) (increment (square (increment x))))])
    (map fun (iota 10)))
> (let ([fun (o increment square increment)])
    (map fun (iota 10)))
  • These are harder to read.
  • Lambda is evil. I like the second one more.
  • The o makes more sense.

Criteria

What criteria would you use in choosing one of these six or so versions over the others?

  • Which is easiest to understand, think about, or read.
  • The speed/efficiency.
    • We could measure experimentally.
    • We could think about it.
      • Count squares and increments. It’s all the same.
      • Count how many things we build. The first one builds a lot more pairs than the other two.
  • Least code.
    • There is generally no relationship between length of code and speed of program.
    • Smaller code feels more elegant.
(define v2 (map (lambda (i) 
                  (increment (square (increment i)))) 
                (iota 10)))

Your responses

Version 1

All of the above methods accomplish the same task, but I prefer the first and fourth methods because they are noticeably less repetitive that methods 2 and 3. If I were to write one myself, I would likely follow a method like the first one because it is both simple (not repetitive) and I am more familiar with the techniques used in method 1 than method 4.

Personally I think v1 is the best way of doing the task at hand. For me, I can easily see the step by step process and explain it to someone else if need be very easily. I’m not sure how expensive v1 is compared to the other options, but if I knew that I would also take that into account in my decision of which one is best.

Of the four procedures defined above, we prefer ‘v1’. Our reason for this is because we’ve used/implemented ‘map’ much more often than the techniques used in ‘v2’, ‘v3’, and ‘v4. Also, ‘v1’ only uses map, square , and increment. The syntax of ‘v1’ is much more readable for novices of scheme such as ourselves.

We prefer the first definition, “v1,” due to the fact that there are clear and easily-understood procedures. For example, The procedures in “v1,” - increment and square - allows us to trace the values of the list as each procedure is applied to each value in this list.

We prefer v1 because it is the most simple and intuitive procedure. It’s very clear and easy to understand. If we were to write the procedure, v1 is probably what we would write.

Version 2

Version 3

I prefer v3, since the composing “f of (g of x)” way of thinking is what makes the most sense to me in Scheme, where parentheses are used in a mathematical way. And though it is the same length as the other 3, because I am comfortable with compose, it seems less cluttered.

Version 4

We prefer v4 because it is the simplest out of all of the procedures. It is is the only one which uses o, which makes it easy to read and clever. I would not have thought of it, but I agree that it is the best procedure out of all four versions.

We prefer v4 because it looks prettier and it may be more efficient because there is only one call to map so it only creates one list. There doesn’t seem to be much difference between the run time of each one.

We prefer v4. v1 calls map three times, creating two additional, unnecessary lists while Scheme processes the function. v2 creates a new procedure within the definition which the procedures may be combined by using compose (as it was done in v4). v3 uses compose but calls compose twice, which is unnecessary based on the task we want to accomplish (again, it can be done with one compose)

We prefer the last one.

  • v1 creates too many lists (by mapping each procedure to the previous list individually), using too much memory.
  • v2 uses lambda, making it ugly and overcomplicated.
  • v3 has nested composes, making DrRacket take an additional step (computing compose square increment) before it can move on to the rest of the procedure.
  • v4 is the most succinct and neat of the procedures, and uses less computational oomph.

After looking at all the possible ways of generating the successors of the squares of the first ten positive integers, we’ve realized that out of all the options available, we’ve preferred option 4. We prefer this because it was the cleanest way of writing the procedure. Option 2 included lambda, which was unnecessarily messy, although it worked. Option 1 was just an extended version of Option 4, but with more maps because they didn’t use compose. Now Option 3 included compose, but didn’t compose all the procedures together, meanwhile Option 4 does this.

We prefer v4 because it is the most concise code. There aren’t repeated calls to ‘map’ as found in v1. In v2 a local procedure has to be defined with nested parentheses. Procedure v3 uses a redundant ‘compose’. Procedure v4 is the most straightforward to read.

We most prefer v4 because it is the most efficient as at applies only one call to map. Also, it is the easiest to understand.

The procedure we liked the best was the 4th one, although a close second was the 1st one. We like the 4th option because it is the least expensive procedure (especially in how o groups the three procedures together in one set of parentheses), but we also liked the 1st one because it was the most readable. Anonymous joked that the 1st procedure is what we would write, but the 4th procedure is what we would be told by Sam to write.

We prefer v4, because there is one large procedure that you are applying to (iota 10), which means it is clear and easy to read. Since this procedure is applied right to left, we know that increment is applied to (iota 10), then square, then increment again. Additionally it’s the shortest definition and accomplishes the same thing with the least amount of commands.

None of the above

We don’t like v1 because it calls map three times which seems inefficient. Similarly, v3 calls compose twice which is also inefficient. We think v2 and v4 are the most efficient, but they both have drawbacks. V2 is nice because it calls lambda and doesn’t use compose, but it looks messy and uses a ton of parantheses. V4 is nice because it is easy to read and the shortest, but it calls both map and compose which isn’t the most efficient way.

Lab

Remember: Three ways to “apply a function to a list”, each with somewhat different meanings.

  • (fun lst)
  • (map fun lst)
  • (apply fun ls)

Writeup

Write up exercise 6 from the lab on higher-order procedures.

Send your solution to csc151-01-grader@grinnell.edu.

Title your email CSC 151.01 Writeup for Class 43 (YOUR FULL NAMES).

Extra Credit

Here’s how most of you wrote acronym.

(define acronym
  (lambda (los)
    (list->string (map (l-s string-ref 0) los))))

How can you make this even more concise?

Email Sam your answer before class on Friday!