简体   繁体   中英

About "Frames as Repository of Local State"

SICP, Exercise 3.10 in section 3.2.3 shows the following as an alternative to a previously defined make-withdraw :

(define (make-withdraw initial-amount)
  (let ((balance initial-amount))
    (lambda (amount)
      (if (>= balance amount)
          (begin (set! balance (- balance amount))
                 balance)
          "Insufficient funds"))))

and prescribes that we

Use the environment model to analyze this alternate version of make-withdraw , drawing figures like the ones above to illustrate the interactions

(define W1 (make-withdraw 100)) (W1 50) (define W2 (make-withdraw 100))

However, before the above request, the text recalls that (let (( <var> <exp> )) <body> ) is syntactic sugar for ((lambda ( <var> ) <body> ) <exp> ) .

Now I guess that suggestion means that I should analize actually this version of make-withdraw :

(define (make-withdraw initial-amount)
  ((lambda (balance)
     (lambda (amount)
       (if (>= balance amount)
         (begin (set! balance (- balance amount))
                balance)
         "Insufficient funds")))
   initial-amount))

or, even better (based on The procedure definition syntax is just syntactic sugar for an underlying implicit lambda expression , from section 3.2.1 ):

(define make-withdraw
  (lambda (initial-amount)
    ((lambda (balance)
       (lambda (amount)
         (if (>= balance amount)
           (begin (set! balance (- balance amount))
                  balance)
           "Insufficient funds")))
     initial-amount)))

And here I see 3 lambda procedures, whereas in both this and this solutions (unofficial; I don't know of official solutions) only two procedures are shown. For instance, this is the latter solution:

; After (define W1 (make-withdraw 100))
 global env
------------------
|                |<--- env: global env
|                |     parameters: initial-amount
| make-withdraw: ----> body:
|                |       ((lambda (balance)
|                |          (lambda (amount)
|                |            (if (>= balance amount)
|                |                (begin (set! balance (- balance amount))
|                |                       balance)
|                |                "Insufficient funds"))) initial-amount)
|                |
|                |       E1
|                |     -----------------------
|                |<----| initial-amount: 100 |
|                |     -----------------------
|                |          /\
|                |       E2 |
|                |     ----------------
|                |     | balance: 100 |
|                |     ----------------
|                |          /\
|                |          |
|                |     env: E2
|                |     parameters: amount
| W1: ---------------> body:
|                |       (if (>= balance amount)
|                |           (begin (set! balance (- balance amount))
|                |                  balance)
|                |           "Insufficient funds")
------------------

whereas I would have imagined that a procedure with parameters: balance and body: (lambda (amount) …) was drawn as well, as that's the (temporary?) lambda that's run in E2 (with balance bound to initial-amount , not to 100 , which is in turn bound to 100 in E1 ) to generate the procedure that's ultimately bound to W1 .

Am I correct? If not, can you explain why?

When (make-withdraw 100) is called it constructs an environment with initial-amount bound to 100 (this is E1 in the diagram). It then immediately calls another function in this environment : that function constructs a child environment in which balance is bound to 100 , which is E2 in the diagram, and returns a third function defined in that environment, which is thus the return value of make-withdraw .

So W1 is now bound to that third function, whose environment is E2 . The second function, which constructed E2 , has been called and has returned its value (the third function): it's no longer in the picture.

That's why it's not there any more.


I'm not sure if it helps, but it might be useful to think of the environment picture if make-withdraw didn't exist at all as its really just spurious noise at the point W1 has been defined (obviously not in real life, where you might want to make several accounts:):

(define W1 ((λ (initial-amount)
              ;; this function was `make-withdraw`
              ((λ (balance)
                 ;; this function was `let`
                 (λ (amount)
                   ;; this is what W1 will end up being
                   (if (>= balance amount)
                       (begin
                         (set! balance (- balance amount))
                         balance)
                       "Insufficient funds")))
               initial-amount))
            100))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM