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)