Prelim 1 is Thursday 10/14, 7:30 pm in B14 Hollister

Review session tonight, 9:30-11:00, 111 Upson.  You are strongly urged to attend, if you want to know what will be on the prelim.

Mini-review the night before the exam (exact place and time TBD).

Last time:

ENVIRONMENT: sequence of FRAMES

FRAME: set of BINDINGS (multiple bindings in same frame don't make sense)

BINDING: variable name and its value

We saw rules for:

 


Extended example

 

(define make-mult
  (lambda (n)
    (lambda (x) (* x n))))

The global environment is pretty big:

Only one frame, but that frame has all the built-in functions in it, and result of any defines

+----------------------------------------+
| + : {add}                              |
| * : {mult}                             |
| ...                                    |
| make-mult: ----------------------------+----> {}{}
+----------------------------------------+

>> Env pointer back to global env

Params: (n)

Body: (lambda (x) (* x n))

 

Now, if we do

 

(define double (make-mult 2))

[How does double print out?]

we build a new frame which points to the global env (because that is where procedure we are applying points to):

+-----------------------------------+
| n : 2                             |
+-----------------------------------+

and add to the global env a binding for double which is a closure

{}{} Params: (x)

Body: (* x n)

>> Points to the environment with n:2

 

 

 

If we

(define triple (make-mult 3))

we'd get another frame

+-----------------------------------+
| n : 3                             |
+-----------------------------------+

The procedure object for triple is like that for double, but with a different environment for n.

>> Write the code object -- could be same code, could just "print the same", different environment!!

>> Enter triple into the global environment

Each procedure that we create this way has its *own* *private* environment, with just n in it.

 


 

(define twice (make-mult 2))

builds *another* such environment. NOT the same [why?]

 

State: functions that return different values, even when called with same arguments. If (barney 23) doesn't always return the same value, then barney has state.

THREE EXAMPLES: [important for prelim #2 and final]

Global state - global

No state - none

Local state - local

(define var 0)

(define global
  (lambda (amt)
    (set! var (+ var amt)) var))

(define none
  (lambda (amt)
    (let ((var 0))
      (set! var (+ var amt))
      var)))

(define local
  (let ((var 0))
    (lambda (amt)
      (set! var (+ var amt))
      var)))

(global 10) == ????? depends on what the value of var is!

if

var = 10

then

(global 10) ==> 20 as long as no intervening computation!

e.g.,

var = 10

(call-any-procedure-at-all)

(global 10) ==> ????? because computation might have changed VAR [This is part of why global variables are such a problem!]

 

(none 10) ==> 10 SHADOWING

always! the local variable VAR is created with value 0

on each call to none, rebound to 10, and then returned.

 

(local 10) ==> ???? [DISCUSS LET IN THE ENVIRONMENT MODEL, BRIEFLY]

depends on the value of the local state variable VAR

if

(local 0) ==> 10

then

(local 10) ==> 20

even if intermediate computation, as long as the intermediate thing does not call local. local is the ONLY procedure that can change the local state variable VAR.

THESE THREE EXAMPLES CONTRAST:

Global state - global

No state - none

Local state - local

 


 

Next example: A simple "account", which only accepts deposits (though you could make negative ones)…

(define make-account
  (lambda (balance)
    (lambda (amt)
      (set! balance (+ balance amt))
      balance)))

(define dino-acct (make-account 10))
(define Barney-acct (make-account 10))

What is the type of these accounts?

(Barney-acct 20) ==> 30

(dino-acct 100) ==> 110

Barney and Dino now have separate accounts, with different balances!

 


 

LOCAL STATE:

In general we use local state variables rather than global ones because code is "safer", in the sense that only certain procedures can have access to these local variables.

Think of "data objects with local state". One way of organizing a system that has objects with local state is the message passing style that we saw earlier in the semester. Now each object not only knows how to process certain messages, it also has local state variables that are particular to each INSTANCE or version of the object of a given TYPE.

(define make-account
  (lambda (balance)
    (lambda (operation)
      (cond ((equal? operation 'deposit)
	     (lambda (amt)
	       (if (> amt 0)
		   (set! balance (+ balance amt))
		   (print "Ahah! Can't deposite a negative amount!"))))
	    ((equal? operation 'withdraw)
	     (lambda (amt)
	       (if (and (> amt 0) (>= balance amt))
		   (set! balance (- balance amt))
		   (print "Your check just bounced!"))))
	    ((equal? operation 'balance)
	     balance)
	    (else (error "Unknown operation"))))))

 

 


Today's concept: LOCAL STATE

Resist Temptation: