束縛(bind)はletの説明のところで出てきたね。
これは一言では意味を表しにくい言葉なんだ。あえて言うなら、局所的に名前と値を結びつけている場所を示す言葉かな。
ひとまず、letを使ったソースを見てみよう。
module Testlet where
f = let x = 4
in x + 10
g x = let x = 2
y = x*3
z = x+10
in x*y+z
h x = let a = x
x = 2
y = x*3
z = x+10
in a*y+z
関数の定義が複数の行にまたがっているけど、関数の本体はinの後の1文だ。
letで括られている文は、関数の本体で使う値を表しているんだ。
一つずつ結果を見ながら説明しよう。
*Testlet> f
14
これは明らかだよね。
わざわざletを使う意味はないけど、説明のためだからね。
xは関数の外では定義されていなかったけど、fの中では使えていることが分かるね。
*Testlet> x
<interactive>:1:0: Not in scope: `x'
xは見つからないって出てくるね。
次にg xだ。
*Testlet> g 0
24
*Testlet> g 1
24
g xのxは結果に反映されていない。
letで新しいxを束縛しているから、g xで代入された値は隠されているのだ。
全く使われていないから、実は何が入っても問題ない。使ってないから意味はないけど。
*Testlet> g "keisan"
24
次はh xである。これはg xとほとんど同じだけれど、xをaで置き換えようとしてみた。
*Testlet> h 0
24
*Testlet> h 1
24
結果はg xと変わらない。let下では順番は関係ないようだ。
実は、というか、前に見た例がそうだけど、インタプリタ上でletを使うと、対話的に値を束縛できる。
*Testlet> pi
3.141592653589793
*Testlet> let pi = 4
*Testlet> pi
4
あまり良い例じゃないけど、piを別の値として使うことが出来る。
関数も定義出来る。
*Testlet> let k x = x + x*x
*Testlet> k 4
20
このインタプリタ上のletは、ソースコード上の剥き出しの定義と同じように使うことが出来る。
実はソースコード上の定義は剥き出しではないけど。
ソースコードの一番始めに書いてある
module Testlet where
これの説明しなければなるまい。
これは、定義が有効になる範囲(スコープ)を表しているんだ。
つまり、今まで関数の定義とか、宣言とか適当に呼んでいたのは束縛だったのだ。
module Xxxが束縛の範囲を表している。
インタプリタで、:moduleとするとPreludeに移動する。
すると、Testletにおいて束縛された値は使えなくなる。
*Testlet> :module
Prelude> f
<interactive>:1:0: Not in scope: `f'
:moduleでTestletに戻ると、ちゃんと使える。
Prelude> :module Testlet
Prelude Testlet> f
14
表示が少し変わったけど、まあいいや。まだ:moduleの使い方が良く分かってないんだよね。
こうやって、束縛する範囲を表すのに、moduleではwhereを使っている。
関数の定義(モジュール下の束縛)にもwhereは使える。
module Testwhere where
f x = x * y
where y = x + 2
whereはこんな風に後に付ける。
同じ範囲にある束縛は、定義された順番に関係なく使えるから、この書き方で問題ないんだ。
これを、説明のために、:loadで読み込む。
するとこんな感じになる。
Prelude Testlet> :load testwhere.hs
Compiling Testwhere ( testwhere.hs, interpreted )
Ok, modules loaded: TestWhere.
*Testwhere> f 2
8
*Testwhere> f (h 2)
<interactive>:1:3: Not in scope: `h'
fはTestwhereのものになって、hはTestwhere下で束縛されていないので使えない。
束縛については良く分かっていないので、今回はこのくらいで。
次は、範囲について説明が必要だと思うけど、それはもう少し後で。
入出力に進んでね。
最終更新:2007年09月28日 19:44