CSC151, Class 24: Local Procedure Bindings Overview: * Local procedures. * letrec and named let. * Writing index. * Lab. Notes: * Miss class when the exam is due, lose lots of points. [Yes, that's sarcastic.] * Optional writeup 2 due. * Exam 1 due. * Read: Pairs and Pair Structures. * HW 3: More Web Services. * Go see the G-Tones. Earn extra credit. * Send me information about three books of your choice (five adjectives each). (list "last-name" "first-name" "title" (list "adj1" "adj2" "adj3" "adj4" "adj5")) ---------------------------------------- Observation: We often build helper functions, particularly when writing recursive functions. General * Verify parameters + Husk-and-kernel precondition checking Specific * For longest list in list + Helper that keeps track of the longest list seen so far. + longer * For tally-skips + Helper took extra parameter (the tally) which kept track of how many things you'd seen Observation again: In general, these "helpers" are not intended for general use. No one else should call them. Hence, we'd like to restrict access to these helpers. (define tally-skips (lambda (lst) (tally-skips-helper lst 0))) (define tally-skips-helper (lambda (lst tally) (cond ((null? lst) tally) ((eq? (car lst) 'skip) (tally-skips-helper (cdr lst) (+ 1 tally))) (else (tally-skips-helper (cdr lst) tally))))) To make this local ... (define tally-skips (letrec ((kernel (lambda (lst tally) (cond ((null? lst) tally) ((eq? (car lst) 'skip) (kernel (cdr lst) (+ 1 tally))) (else (kernel (cdr lst) tally)))))) (lambda (lst) (kernel lst 0)))) Key moral: For a local recursive procedure, use letrec rather than let or let*. Since it's local, you might as well call it "kernel" or "kernal" or "colonel" or "helper" * Make sure to use the same name everywhere in the same procedure. Here's another way to define recursive helper procedures (let name ((param1 exp1) (param2 exp2) ... (paramn expn)) body) This is a "named let". Looks like a normal let, acts very differently. * Defines a procedure named name * whose parameters are param1 ... paramn * Calls that procedure with arguments exp1 ... expn Shorthand for (letrec ((name (lambda (param1 ... paramn) body))) (name exp1 ... expn)) Here's tally-skips using named let (define tally-skips (lambda (lst) (let kernel ((remaining lst) (tally 0)) (cond ((null? remaining) tally) ((eq? (car remaining) 'skip) (kernel (cdr remaining) (+ 1 tally))) (else (kernel (cdr remaining) tally)))))) ---------------------------------------- Why does Sam restrict what you can say about exams. "You may not help other people". * Although this is a "Well, Duh" statement, I've been burned by students who claim that I don't say it. "You must tell me if other students cheat". * Removes moral quandries. * You don't need to tell me who. "You must not tell other students how much you've done" * What purpose does that serve, other than making you feel good (and, presumably, others feel bad). "You should not discuss your exam results with others" * What purpose does that serve? (ACP says Help you learn from someone who did well. That's a good reason.) ---------------------------------------- 1c. Should look something like: (letrec ((last-of-list ...)) (+ (last-of-list (list 1 2 3)) (last-of-list (list 7)) (last-of-list (list 4 2 1 4))))