SICPを読む(96) 問題 3.7 - 共同口座
ムズイな。
問題 3.7
パスワードつき銀行口座を改造して、共同口座を作れ。という問題。
口座は同じで、パスワードが違うように設定する。
問題は、パスワードを変更してしまうと、引きずられて、元のパスワードまで変わってしまう点。
ユーザーオブジェクトを中に仕込むのは大変そうなので、make-accountの変更点は一箇所。パスワードが合っているのか確認するだけ。
make-jointで、アカウント作成時に作ったパスワードを保持できるので、実際にはアカウント作成時のパスワードでログインすることにする。
(define (make-account balance pass) (let ((incorrect 0)) (lambda (p m) (let ((withdraw (lambda (amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) (error "Insufficient funds"))))) (cond ((eq? p 'check-pass) (eq? pass m)) ((eq? p pass) (case m ('withdraw withdraw) ('deposit (lambda (x) (withdraw (- x)))))) (else (begin (set! incorrect (+ incorrect 1)) (if (<= incorrect 3) (error "Incorrect password.") (error "逮捕します。"))))))))) (define (make-joint account pass joint-pass) (if (account 'check-pass pass) (lambda (p m) (if (eq? p joint-pass) (account pass m) (error "Incorrect password."))) (error "Incorrect password.")))
テスト。
(define peter-acc (make-account 100 'open-sesame)) ((peter-acc 'open-sesame 'withdraw) 10) ; 90 (define paul-acc (make-joint peter-acc 'hoge-hoge 'rosebund)) ; Incorrect password. (define paul-acc (make-joint peter-acc 'open-sesame 'rosebund)) ((paul-acc 'open-sesame 'withdraw) 10) ; Incorrect password. ((paul-acc 'rosebund 'withdraw) 10) ; 80 ((peter-acc 'open-sesame 'withdraw) 10) ; 70
ここまではうまくいってるんだけど、
「孫アカウントは作れない」
ちと動作もおかしい。
解決。
(define (make-joint account pass joint-pass) (if (account 'check-pass pass) (lambda (p m) (cond ((eq? p 'check-pass) (eq? joint-pass m)) ((eq? p joint-pass) (account pass m)) (else (error "Incorrect password.")))) (error "Incorrect password.")))
親と同じようにしてやればいいんだ。
- 孫アカウント作成時には親の認証は済んでるはずなので、親までは見に行かないようにした。
- ログインした場合は再帰的に問い合わせていく。
口座オブジェクトと、アカウントオブジェクトを別にしたほうがわかりやすいけど、再帰的になってるアカウントというのも面白いね。