問題3.7 – SICP(計算機プログラムの構造と解釈)その109

問題3.7

最初に考えた解答

パスワードをリストにして、複数のパスワードが利用出来るようにする。
パスワード追加手続き add-password を定義する。
パスワードのリストから一致するパスワードを探す correct-password? を定義する。

(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
                     balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (add-password new-password)
    (set! password (cons new-password password))
    password)
  (define (correct-password? pass)
    (memq pass password))
  (define (dispatch pass m)
    (if (correct-password? pass)
        (cond ((eq? m 'withdraw) withdraw)
              ((eq? m 'deposit) deposit)
              ((eq? m 'addpassword) add-password)
              (else (error "Unknown request -- MAKE-ACCOUNT" m)))
        (error "Incorrect Password" pass)))
  dispatch)

;; 共同口座を作る手続き make-joint
(define (make-joint account account-password new-password)
  (begin ((account account-password 'addpassword) new-password)
         account))
実行結果

一見上手くいったかと思ったけれど、お互いのパスワードを使うことができてしまう。

;; peter の口座
(define peter-acc (make-account 100 '(open-sesame)))
((peter-acc 'open-sesame 'withdraw) 20)
gosh> 80
;; paul の口座
(define paul-acc (make-joint peter-acc 'open-sesame 'rosebud))
((paul-acc 'rosebud 'withdraw) 20)
gosh> 60
((peter-acc 'open-sesame 'deposit) 20)
gosh> 80
((paul-acc 'rosebud 'withdraw) 30)
gosh> 50
((peter-acc 'open-sesame 'withdraw) 30)
gosh> 20
((paul-acc 'open-sesame 'withdraw) 10)
gosh> 10
((peter-acc 'rosebud 'withdraw) 10)
gosh> 0

パスワードの使い回しができないようにした解答

make-account には手を加えずに、make-joint で追加口座のパスワードを管理する。

(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
                     balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (dispatch pass m)
    (if (eq? pass password)
        (cond ((eq? m 'withdraw) withdraw)
              ((eq? m 'deposit) deposit)
              (else (error "Unknown request -- MAKE-ACCOUNT" m)))
        (error "Incorrect Password" pass)))
  dispatch)

(define (make-joint account account-password new-password)
  (define (dispatch password m)
    (if (eq? password new-password)
        (account account-password m)
        (error "Incorrect password" account-password)))
  dispatch)
実行結果
;; peter の口座
(define peter-acc (make-account 100 'open-sesame))
((peter-acc 'open-sesame 'withdraw) 20)
gosh> 80
;; paul の口座
(define paul-acc (make-joint peter-acc 'open-sesame 'rosebud))
((paul-acc 'rosebud 'withdraw) 10)
gosh> 70
((paul-acc 'rosebud 'deposit) 10)
gosh> 80
((paul-acc 'open-sesame 'deposit) 10)
gosh> *** ERROR: Incorrect password open-sesame
((peter-acc 'rosebud 'withdraw) 10)
gosh> *** ERROR: Incorrect Password rosebud
計算機プログラムの構造と解釈
ジェラルド・ジェイ サスマン ジュリー サスマン ハロルド エイブルソン
ピアソンエデュケーション
売り上げランキング: 6542
«
»