パターンマッチとか
『プログラミング言語』(武市正人)のなかに,
data Val = V_Int Int | V_Bool Bool expval (Bexpr o e e') r = V_Int (binopr o v v') where V_Int v = expval e r V_Int v' = expval e' r
というようなコードが出てくる。
学部4年のときに読んだときは,whereのあとの"V_Int V = ..."のところの書き方がイマイチよくわからなかった。なんで"V"の前に代数データ型の構成子があるんだ?構成子を関数のように使うのなら,つまり,"V = V_Int (expval e r)"のような形ならわかるのだが・・・。といった感じだった。結局,よくわからないけどHaskell*1ではこういう風に書ける,ということで納得して本を読み進めていった。まあ,おまじないにしてしまったわけだ。
で,1年半後。"V_Int v = expval e r"はパターンマッチであることに気づいた。"expval e r"の結果が"V_Int 100"だとすると,"V_Int v"と"expval e r"が等しくなるためにはvの値は100である必要がある。なので"v = 100"となる。よくよく考えると"(x,y) = (1,2)"みたいなのと同じなわけで,"(x,y) = (1,2)"は違和感なかったわけだから代数データ型がよくわかってなかったんだろうなあ。まあ,今も理解してるとは言えないが。
さて,パターンマッチということは"let 0 = 0 in 1"みたいなのもプログラムとして正しいはず。実際にGHCで試すと,
Prelude> let 0 = 0 in 1 1
となり,ちゃんと評価されている。と思いきや,
Prelude> let 0 = 1 in 1 1
となるので何とも言えない。しかし,
Prelude> let (x,2) = (1,2) in x 1 Prelude> let (x,2) = (1,3) in x *** Exception: <interactive>:1:4-16: Irrefutable pattern failed for pattern (x, 2)
となるので,"let 0 = 1 in 1"のときはletの宣言部がその後の処理に影響を与えない,というか変数宣言になっていないので,評価器が宣言部を評価していないと考えられる。Haskellの仕様かGHCの実装かはわからないが(←調べろよ)。
ここで気になるのは,関数定義のときの"="の捉え方。関数定義の"="はパターンマッチではないのだから,"="は二つの意味で使われているわけか。
V_Int v = expval e r sq x = x * x
上はパターンマッチだが,下はパターンマッチではない。だけど同じ記号を使っている。"sq x = x * x"は
sq = \x -> x * x
のSyntax Sugarだろうから,本質的にやってることは同じなんだろうけど,なんか気持ち悪いな。
*1:本の中で使われているのはGoferだが