読者です 読者をやめる 読者になる 読者になる

(wat-aro)

無職から有職者にランクアップしました

SICP 問題 3.48

scheme SICP
;; 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.co

と教えていただいたので書き換えました.
二回比較するのが嫌だったんですよね.

;; 口座番号の小さいほうから先に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)))))