2015/12/06
SICP 問題 3.48
;; make-accountの引数にidを追加.
;; dispatchの引数に'numberで口座番号を参照できる.
(define (make-account-and-serializer balance id)
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))
(define (deposit amount)
(set! balance (+ balance amount))
balance)
(let ((balance-serializer (make-serializer)))
(define (dispatch m)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
((eq? m 'balance) balance)
((eq? m 'id) id)
((eq? m 'serializer) balance-serializer)
(else (error "Unknown request: MAKE-ACCOUNT" m))))
dispatch))
(define (exchange account1 account2)
(let ((difference (- (account1 'balance)
(account2 'balance))))
((account1 'withdraw) difference)
((account2 'deposit) difference)))
;; 口座番号の小さいほうから先にserialize.
(define (serialized-exchange account1 account2)
(let ((id1 (account1 'id))
(id2 (account2 'id)))
(let ((smaller (if (< id1 id2) account1 account2))
(bigger (if (< id1 id2)) account2 account1))
(let ((serializer1 (smaller 'serializer))
(serializer2 (bigger 'serializer)))
((serializer2 (serializer1 exchange))
account1 account2)))))
smallerとbiggerへの束縛のいい方法がわからずtwitterで聞いたところ,
t.coR7RS (というか let-values が使える環境) ならこんな感じかなぁ。 (let-values (((x y) (if (< a b) (values a b) (values b a)))) body ...)
— 齊藤敦志 (@SaitoAtsushi) December 6, 2015
と教えていただいたので書き換えました.
二回比較するのが嫌だったんですよね.
;; 口座番号の小さいほうから先にserialize.
(use srfi-11)
(define (serialized-exchange account1 account2)
(let ((id1 (account1 'id))
(id2 (account2 'id)))
(let-values (smaller bigger)
(if (< id1 id2)
(values id1 id2)
(values id2 id1))
(let ((serializer1 (smaller 'serializer))
(serializer2 (bigger 'serializer)))
((serializer2 (serializer1 exchange))
account1 account2)))))