SICPを読む(89) 3.1.1 set!

Scheme環境が整ってきたので3章に入ろう。


銀行システムを作っていくみたい。

(define *balance* 100)

(define (withdraw amount)
  (if (>= *balance* amount)
      (begin (set! *balance* (- *balance* amount)) *balance*)
      "お金が無いっす!!"))

(withdraw 25) ; 75
(withdraw 25) ; 50
(withdraw 60) ; お金が無いっす!!

3章に入ってやっとset!が出てきたけど、これは気持ち悪い。

  • *グローバル*としてみたけど、グローバル変数が気持ち悪い。
  • set!が値を返さないと言うのが気持ち悪い。
  • beginが気持ち悪い。
  • 同じように関数を呼んだのに帰ってきた値が違う。

うぅん気持ち悪い。破壊的になると激しくプログラムを追いにくくなるということがよくわかった気がする。


関数型言語に慣れるとこういうのが弊害になるんだろうなぁ・・・慣れるのに時間がかかりそうだ。


さてと、グローバルは気持ち悪いので、クロージャにする。

(define (new-withdraw balance)
  (lambda (amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount)) balance)
       "お金が無いっす!!")))

(define W (new-withdraw 100))
(W 25) ; 75
(W 25) ; 50
(W 60) ; お金が無いっす!!

let無しの、チト改造版。まだ気持ち悪さ満載だけど幾分マシになった気がする。

クロージャの解説によく出てくる感じの奴。クロージャの解説にこのサンプルを使うのはどうかと思う。

クロージャとは - はてなダイアリー


しまった。次の解説がlet無しバージョンだった。急ぎすぎた。


次。預金システム。

(define (make-account balance)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount)) balance)
       "お金が無いっす!!"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (lambda (m)
    (cond ((eq? m 'withdraw) withdraw)
          ((eq? m 'deposit) deposit)
          (else (error "error -- " m)))))

(define tanaka (make-account 100))
((tanaka 'withdraw) 25) ; 75
((tanaka 'withdraw) 25) ; 50
((tanaka 'deposit) 150) ; 200

オブジェクト指向風な展開になってきた。これはおもろいかも。

アカウントをたくさん持っても管理出きるね。