パターンマッチとか

プログラミング言語』(武市正人)のなかに,

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だが