Search code examples
schememit-scheme

Defining a function to call nested functions


I have been working through an online scheme tutorial and am confused about the following code:

(define make-bank-account
  (lambda (balance)
    (display "Ding")
    (lambda (n)
      (display "Dong")
      (set! balance (+ balance n))
      balance)))

(define account1 (make-bank-account 10))

;; My code
(define account2
  (lambda (x)
    ((make-bank-account 10) x)))

Why is it that account2 does not accumulate the balance from call to call, while account1 does? For example:

(account1 5)
-> Dong
;Value: 15

(account1 10)
-> Dong
;Value: 25

(account2 5)
-> DingDong
;Value: 15

(account2 10)
-> DingDong
;Value: 20

I have tested the code using "Ding" and "Dong" and noticed that when calling account1 "Ding" is never displayed while calling account2 both "Ding" and "Dong" are displayed. I believe this corresponds with the issue. Thanks in advance!


Solution

  • In your code, you're creating a new function every time you call it, because the function you return includes a new call to make-bank-account. If you change it slightly to:

    (define account2
        (lambda (x)
            (account1 x)))
    

    obviously you would get the correct functoning. account1, however, calls the make-bank-account and uses the function returned, that "holds" the placeholder with the correct value when you call it repeatedly.

    To show the difference, you can "remember" the account you created. This is essentially the same original code:

    (define new-account
      (lambda (initial-amount)
        (define my-account (make-bank-account initial-amount))
        (lambda (amount)
          (my-account amount))))
    

    Note how the function you return (the second lambda) already has initialized the my-account, with just one call to make-bank-account. Then, to create a new account:

    > (define account3 (new-account 20))
    Ding
    > (account3 30)
    Dong50
    > (account3 30)
    Dong80
    >