CSC 151.03, Class 30: Analyzing procedures
Overview
- Preliminaries
- Notes and news
- Upcoming work
- Extra credit
- Questions
- Debrief on yesterday’s lab.
- Quick review of homework 6.
- Lab.
News / Etc.
- If you take notes on the gridded pads, please take, discard, or recycle your notes. MOre generally, please keep your work area clean.
- We will probably not get through more than half of today’s lab today. That’s okay. There’s lab time on Friday.
- It’s preregistration time. Things to consider:
- CSC 161 is an awesome course. I’m told it’s very different than
- (For some, that’s a positive. For others, that’s a negative.)
- Wilson short course: Human Centered Design for Global Social Transformation
- Wilson short course: Leadership in a Future of Automation and Income Inequality.
- ENG 295-01. Lighting the Page: Digital Methods in Literary Studies. (ENG-120 prereq)
- HIS 295-01. Digital Methods in Historical Studies. (HIS-100 prereq)
- CSC 161 is an awesome course. I’m told it’s very different than
Upcoming Work
- Writeup for class 29 due TONIGHT at 10:30 p.m.
- Exercise 6, no documentation necessary.
- To: csc151-03-grader@grinnell.edu
- Subject: CSC 151.03 Writeup 29 (YOUR NAMES)
- No writeup for today’s class.
- Read Project description for Friday’s class.
- No, it’s not ready.
- Exam 3
- Prologue due Friday.
- Exam due Tuesday the 14th.
- Cover pages due Wednesday the 15th.
- Epilogues due Wednesday the 15th.
- Quiz Friday
- Trees
- Higher-order procedures
- Files
- Don’t forget mentor sessions.
Extra credit (Academic/Artistic)
- Crip Technoscience, Disabled People as Makers and Knowers, Wednesday, Nov. 8, 4:15 p.m., JRC 101.
- Workshop by Sanjay Khanna ‘85 “Khanna can pitch. Can you?” Tonight at 7pm in ARH 120. Sign up at https://grinnell.co1.qualtrics.com/jfe/form/SV_8B7YaJkixNUBmjH
Extra credit (Peer)
Extra credit (Misc)
- Pioneer weekend. (Today is the last day to sign up.)
Other good things
- Pub Quiz tonight!
- Anime talk tomorrow night. See below.
Spirit/Medium/Media: A Critical Examination of the Relationship Between Animism, Animators, and Anime Thursday, Nov. 9 7:30 p.m., Burling Library Lounge
Jolyon Thomas ‘01 critiques the argument that Japanese animation is thematically and aesthetically unique because it draws upon Japan’s ancient animistic traditions, which are based on the belief that objects, places, and creatures all possess a distinct spiritual essence. He argues that when professional observers describe anime as “animistic,” they use a politically weighted and technically inaccurate term to engage in political projects related to environmentalism or cultural nationalism.
Questions
On the exam
On the analysis reading
- Why don’t we just use
timeto measure the efficiency of the program? - We generally work with such small inputs that the time is 0.
- Thinking with small data sets lets you think with large data sets.
- Allows you to measure only what you care about.
On other topics
- Will you finish writing assignment 7?
- Probably not.
- But I’ll incorporate it into the project as an option.
Debrief from prior class
How did you figure out that the sum was correct?
(apply + (map string->number (file->words FILE)))- Open the file in DrRacket. Put
(+at the start. Put ‘)’ at the end. Evaluate. - Open the file in a spreadsheet and use the spreadsheet sum.
Writing file-size
Start with the code for sum-of-file.
(define sum-of-file
(lambda (file-name)
(let ([source (open-input-file file-name)])
(let kernel ([sum-so-far 0])
(let ([nextval (read source)])
(cond
; Are we at the end of the file?
; Then stop and return our running sum.
[(eof-object? nextval)
(close-input-port source)
sum-so-far]
; Have we just read a number?
; If so, add it to the sum of the remaining numbers.
[(number? nextval)
(kernel (+ nextval sum-so-far))]
; Hmmm ... not a number. Skip it.
[else
(kernel sum-so-far)]))))))
Update name, mechanism for reading, etc.
(define file-size
(lambda (file-name)
(let ([source (open-input-file file-name)])
(let kernel ([sum-so-far 0])
(let ([nextval (read-char source)])
(cond
; Are we at the end of the file?
; Then stop and return our running sum.
[(eof-object? nextval)
(close-input-port source)
sum-so-far]
; Have we just read a number?
; If so, add it to the sum of the remaining numbers.
[(char? nextval)
(kernel (+ 1 sum-so-far))]
; Hmmm ... not a number. Skip it.
[else
(kernel sum-so-far)]))))))
Clean up a bit
(define file-size
(lambda (file-name)
(let ([source (open-input-file file-name)])
(let kernel ([sum-so-far 0])
(let ([nextval (read-char source)])
(cond
[(eof-object? nextval)
(close-input-port source)
sum-so-far]
[else
(kernel (+ 1 sum-so-far))]))))))
Notes on HW6
Disclaimer: I’ve been programming in Scheme for longer than any of you have been alive. I’ve even been programming in Scheme for more than the sum of the time all of you have been programming in Scheme. I just solved all of these problems this morning. You should expect to take significantly longer than I took, but you should look for key points.
Problem 1 - partition
- To partation a list into k lists, figure out the size of the first list, build the first list, recurse on the rest, and put it all together.
- E.g., if the list has ten elements and we want to divide it into four parts, the first part has three elements (10/4), pull off three elements and then divide the remaining seven elements into three pieces.
#lang racket
(require csc151)
;;; Procedure:
;;; partition
;;; Parameters:
;;; lst, a list
;;; k, a positive integer
;;; Purpose:
;;; Break lst up into k more-or-less-equal length list
;;; Produces:
;;; lol, a list of lists
;;; Preconditions:
;;; [No additional]
;;; Postconditons:
;;; lol contains k lists.
;;; (reduce append lol) = lst
(define partition0
(lambda (lst k)
; What's the base case?
(if (= k 1)
(list lst)
(cons (take lst (ceiling (/ (length lst) k)))
(partition0 (drop lst (ceiling (/ (length lst) k)))
(- k 1))))))
(define partition2
(lambda (lst k)
; What's the base case?
(if (= k 1)
(list lst)
(let ([okay-size (ceiling (/ (length lst) k))])
(cons (take lst okay-size)
(partition2 (drop lst okay-size)
(- k 1)))))))
; Where should we put the `let`? Generally, at the first point you need or can
; compute the value. (A bit of a balancing act.)
; Improving the code
; 1. Add a husk. (Not today.)
; 2. Avoid so many calls to length. Keep track of the length
(define partition
(lambda (lst k)
(let kernel ([remaining lst]
[pieces k]
[len (length lst)])
(if (= pieces 1)
(list remaining)
(let ([okay-size (ceiling (/ len pieces))])
(cons (take remaining okay-size)
(kernel (drop remaining okay-size)
(- pieces 1)
(- len okay-size))))))))
; Learning outcomes?a
; * Learn to satisfice. Your code may never be perfect. But think about
; *reasonable* ways to make it better.a
; * Simplify from a working solution
; * Limit recursion
; Palindrome
; Our goal was that you not recurse through a list. We wanted you to work
; with the string directly.
; Idea: Work from ends.
; Strings have a string-ref procedure. string-ref is about as efficient
; as vector-ref. (IN some languages, strings are mostly vectors of characters.)
(define palindrome
(lambda (str)
(let kernel ([left 0]
[right (decrement (string-length str))])
(or (>= left right)
(and (char=? (string-ref str left) (string-ref str right))
(kernel (increment left) (decrement right)))))))
; Observation: We could use conditionals, which better match how we
; talk about it.
(define pal?
(lambda (str)
(let kernel ([left 0]
[right (decrement (string-length str))])
(if (>= left right)
#t
(if (char=? (string-ref str left) (string-ref str right))
(kernel (increment left) (increment right))
#f)))))
; The two are similar in efficiency. Sam finds the first more
; elegant and perhaps even more readable. Your experience may
; be different than mine. (YEMBDTM)
; Working with kernels is often useful.
; Create a new list by inserting val at the specified position
; in the list.
; The position has to be between 0 and length, inclusive
; Sam's intuition: Direct recursion may work here.
(define insert-at
(lambda (lst pos val)
; Base case: Insert at the front, which I can do when pos is 0
(if (zero? pos)
(cons val lst)
; Insert the value in the cdr
; Add the front back on
(cons (car lst)
(insert-at (cdr lst)
(decrement pos)
val)))))
(define remove-at
(lambda (lst pos)
; Base case: Insert at the front, which I can do when pos is 0
(if (zero? pos)
(cdr lst)
; Insert the value in the cdr
; Add the front back on
(cons (car lst)
(remove-at (cdr lst)
(decrement pos))))))
; Problem 4: insert-everywhere
; Basic idea: call insert-at with 0 1 2 3 ... length
(define insert-everywhere
(lambda (val lst)
(let ([len (length lst)])
(let kernel ([pos 0])
; Base case: Stop when pos exceeds length
(if (> pos len)
null
(cons (insert-at lst pos val)
(kernel (increment pos))))))))
; permutations is already defined. I'm done.
; Obs: If I have the permutations of (2 3 4), I can get the permutations of
; (1 2 3 4) by inserting 1 into the first permutation and then inserting 1
; into the second perm, ...
(define perms
(lambda (lst)
(if (or (null? lst) (null? (cdr lst)))
(list lst)
(let ([first (car lst)]
[partial-permutations (perms (cdr lst))])
(let kernel ([remaining partial-permutations])
(if (null? remaining)
null
(append (insert-everywhere first (car remaining))
(kernel (cdr remaining)))))))))