名前付きlet
9章5節。名前つきlet。
今回はRPGを想定して、以下のようなプレイヤーの状態をを表す連想リストを規定してみる。
((hp . 320) ; 体力 (mp . 66) ; 魔力 (position . #f) ; 現在位置 (inventory potion potion dagger cookie dagger) ; 持ち物 )
「ポーション飲んだらポーションが減った」だけじゃ面白くないので、今後の展望としては、状態を変化させてみよう、という流れになるのだろう。
まずはその足がかりとして、今回はプレイヤーを作成するための手続きmake-playerを考える。
(make-player 'hp 320 'mp 66 'position #f 'inventory '(potion potion dagger cookie dagger))
のように評価すると、上で述べた状態の連想リストを生成するとする。
この式を見て思ったのが、キーワード引数の形に似てるなぁー、ってこと。
でも、キーワード引数にしてしまうと、例えばプレイヤー状態に「レベル」が追加された時に、make-playerを書き換えないといけなくなるから不便だな。うん。
ってことで、make-playerを定義してみる。
(define make-player (lambda args (define loop (lambda (lis) (match lis (() '()) ((attr value . rest) (cons (cons attr value) (loop rest)))))) (loop args)))
んじゃ、使ってみる。
gosh> (make-player 'hp 320 'mp 66 'position #f) ((hp . 320) (mp . 66) (position . #f)) gosh> (make-player 'hp 320 'mp 66 'position) *** ERROR: : no matching clause for (position) Stack Trace: _______________________________________ 0 loop 1 loop
うむ、引き数は必ず偶数にする必要があるのか。
いままで何回もローカル手続きloopを使ってきた。
この方法は、手続きの実行に先立って手続きの定義があるので、定義が長くなる場合に見通しが悪くなる。...らしい。
ということで、シンタックスシュガーが用意されているらしい。
それが以下の名前付きlet。
(use util.match) (define make-player (lambda args (let loop ((lis args)) (match lis (() '()) ((attr value . rest) (cons (cons attr value) (loop rest)))))))
要は手続きの実行の同時に名前を束縛するわけですな。