ダイヤ「これまでdefine
を使って定義したグローバル変数を扱ってきました」
果南「プログラムのどこからでも見える変数だよね」
ダイヤ「はい。ですが、変数の有効範囲を局所化することができます。名前の衝突を避けるなどの理由で、一般に変数はできるだけ狭いスコープで使うことが望ましいとされますわ」
ダイヤ「利用できる範囲の限定される変数については、触れはしませんでしたがすでに出てきていますわ。lambda
を思い出してください」
1 2 3 4 |
(define x 10) (define double (lambda (x) (+ x x))) (double 5) ; 10 (double x) ; 20 |
ダイヤ「グローバル変数x
を定義し、また手続きdouble
を定義してその中で変数x
を使っています」
花丸「それで、(double 5)
ではx
は5になるから(+ 5 5)
で10ずら」
ダイヤ「ですが、最初に定義したグローバル変数x
と、手続きdouble
が引数に取るx
は別のものなのです」
果南「えーと、double
の中でx
の値が5に変更されるとしたら、最後の(double x)
は10にならないとおかしいのか」
ダイヤ「はい。ですが実際には20になりますね。これはつまり、手続きdouble
で使われるx
は手続きdouble
の中だけで有効なローカル変数ということです」
花丸「lambda
の中で何をしてもグローバル変数には影響しないってことかー」
ダイヤ「lambda
で手続きを作らなくてもローカル変数を利用する方法があります」
1 2 3 4 5 |
(define dia "kurosawa") (define kanan "matsuura") (define maru "kunikida") (let ((dia 80) (kanan 83) (maru 83)) (/ (+ dia kanan maru) 3)) ; 82 (display dia) ; "kurosawa" |
ダイヤ「・・・くっ」
果南「別にそんな自虐的にならなくても・・・」
ダイヤ「・・・ともかく。lambda
と同じように、let
の本体部分だけで有効な変数を利用できます」
花丸「lambda
より簡単に書ける感じがするずら」
ダイヤ「では、この例を見てください」
1 |
(let ((dia 80) (kanan (+ dia 3)) (maru kanan)) (/ (+ dia kanan maru) 3)) ; ERROR |
花丸「同じ結果になりそうに見えるけど・・・エラーになるずら」
ダイヤ「ローカル変数の有効範囲はあくまでlet
の本体だけ。ですから、初期化の段階で他のローカル変数を参照することはできないのです」
果南「理屈は分かるけど、できた方が便利だったりしない?」
ダイヤ「そのための書き方も用意されていますわ」
1 |
(let* ((dia 80) (kanan (+ dia 3)) (maru kanan)) (/ (+ dia kanan maru) 3)) ; 82 |
ダイヤ「let*
を使うと、前に初期化した変数を後から出てくる変数の初期化に使うことができます」
果南「kanan
の初期化のところでは初期化済みのdia
を使える、と」
ダイヤ「let
やlet*
はlambda
を使って書くこともできますから、お暇な方は試してみるとよいかと思いますわ」
ダイヤ「次回はSchemeにおける繰り返し、再帰について見ていきますわ」
花丸「ようやくプログラムらしいプログラムが書けるようになるずら」
果南「再帰・・・再帰か・・・」