CSC151, Class 22: Local Bindings Overview: * Why name things * Naming things with let * An application * A variants: let* Notes: * Questions on exam 1? * Yes, I'm still working on grading homework 2. * YA primarily lecture class How do I spell check my exam? (1) Save it as a plain text file from DrScheme (2) Open a terminal window (3) Type spell povilas-exam.ss Detour: The story of Gauss K : 1 + 2 + 3 + 4 + ... + n-2 + n-1 + n K : n + n-1 + n-2 + ..... + 3 + 2 + 1 ------------------------------------------------------------ 2K:1+n + 1+n + 1+n + ..........+ 1+n + 1+n + 1+n 2K = (1+n)n Therefore K = n(n+1)/2 ---------------------------------------- It is helpful to name things in programs. You know how to name some things * Values * Procedures * Parameters Sometimes you want to name something new within a procedure. * Value * Procedure (define largest (lambda (lst) ; Figure out the base case. (if (length-one? lst) (car lst) (let ((first-element (car lst)) (largest-remaining-element (largest (cdr lst)))) (larger first-element largest-remaining-element) Naming in this procedure: (1) (null? (cdr lst)) is somewhat confusing. It would be nicer to have length-one? predicate (2) larger is not yet defined (3) For novice programmers, it's not clear what what (largest (cdr lst)) is. ;;; Procedure: ;;; length-one? ;;; Parameters: ;;; lst, a list ;;; Purpose: ;;; Determines if the length of lst is 1. ;;; Produces: ;;; it-has-only-one-element, a Boolean value ;;; Preconditions: ;;; lst must be a list. ;;; Postcondiitons: ;;; If lst contains only one element, ihooe is #t. ;;; Otherwise, ihooe is #f. (define length-one? (lambda (lst) (and (not (null? lst)) (null? (cdr lst))))) Standard form of a let statement (let ((NAME1 EXP1) (NAME2 EXP2) ... (NAMEN EXPN)) BODY) Meaning: (1) Evaluate EXP1 through EXPN (2) Remember that the names NAME1 through NAMEN are associated with the valeus of those expressions. (3) Evaluate BODY using those new names. > (define a 2) > (let ((b 4)) (+ a b)) 6 a: 2 b: 4 > (let ((b 4) (a 5)) (+ a b)) 9 > (let ((a 4) (b a)) (+ a b)) > (let ((b a) (a 4)) (+ a b)) Initially, a: 2 a : 4 b : 2 (define a 2) (list (let ((a 4)) a) a) ; (4 2) (define a 2) (cons (let ((a 4)) (cons (let ((a 5)) a) (cons a null))) (cons a null)) ; OUTSIDE OF THE LET, a goes back to its old value. What's the benefit of doing all of this local naming? * You can choose names without worrying about them interfering with other people's names. We can define procedures locally. (define sum-of-squares (lambda (lst) (let ((square (lambda (x) (* x x)))) (if (null? lst) 0 (+ (square (car lst)) (sum-of-squares (cdr lst))))))) (define sum-of-squares (let ((square (lambda (x) (* x x)))) (lambda (lst) (if (null? lst) 0 (+ (square (car lst)) (sum-of-squares (cdr lst))))))) (define dan (if (> a 2) (lambda (x) x) (lambda (x) 2))) ---------------------------------------- You cannot use let to define recursive procedures. (Blah.) You can define things in sequence without nesting lets. (let* ( (a 4) (b (* a a))) b)