ex 3.7

基本方針としては、
パスワードをリストで管理することにして、
パスワード付きアカウントを作成するmake-password-accountに
新しいメソッドとして、パスワード追加を行うadd-new-passwordを追加。

;; ex 3.7
;; パスワード付きアカウント作成
;; パスワードのリストを内部的に持つようにして、新しいパスワードを追加する add-new-passwordを追加
(define (make-password-account balance password)
  (define password-list (list password))
  (define (add-new-password new-password)
    (set! password-list (cons new-password password-list)))
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount)))
  (define (dispatch pass m)
    (if (memq pass password-list)
        (cond ((eq? m 'withdraw) withdraw)
              ((eq? m 'deposit) deposit)
              ((eq? m 'add-new-password) add-new-password)
              (else (error "Unknown request -- MAKE-PASSWORD-ACCOUNT")))
        (lambda (a) "Incorrect password")))
  dispatch)

;; account に新しいパスワードを追加して、accountを返す
(define (make-joint account account-password new-password)
  (begin ((account account-password 'add-new-password) new-password)
         account))

実行結果は

gosh> (define peter-acc (make-password-account 100 'open-sesame))
peter-acc
gosh> (define paul-acc (make-joint peter-acc 'open-sesame 'rosebud))
paul-acc
gosh> ((peter-acc 'open-sesame 'withdraw) 10)
90
gosh> ((paul-acc 'rosebud 'withdraw) 20)
70
gosh> ((peter-acc 'open-sesame 'withdraw) 0)
70