Hindley/Milner type systemのこと

しばらく更新を怠っていました。今もまだ余り時間が取れないのですが、Doukaku.orgの問題を少し見る余裕が出てきました。平行して、いくつかHaskell関係の論文を読んでいたのですが、そのうちの一つ、Functional Programming with Overloading and Higher-Order Polymorphism (http://web.cecs.pdx.edu/~mpj/pubs/springschool.html) を読んでいて発見したことをかきます。

Haskellでも使われている型宣言文法であるHindley/Milner type system (以降HM)はそのおおもとのアイディアはなんと1969年に考案されていたようです…Fortran(1960年代)やLisp(1965年)に比べれば後にはなりますが、C(1972年)よりも前からあるものなんですね...ちょっと驚きました。

件の論文なのですが、HMの概略、classの導入、kind(時々コンパイルエラーで食らう*->*->*です...)の概略などが解説されていて、参考になりました。

HMといえば、型変数や型推論が便利だったり:
 length :: [a] -> Int --リストが保持する値の型は特に指定しなくても良い。
僕がすごいと思うのは、入力パラメタと帰り値の統合の仕方です…

例えば+演算子の型は:
(+) :: (Num a) => a -> a -> a
なわけで、Numクラスの型である値を二つとって、同じ型の値を返す関数とも読めるし、
Numクラス型である値を一つとって、(a->a)な関数を返す関数とも取れる。:
(+) :: (Num a) => a -> (a -> a)

これは、C言語などに見る
int add(int i, int j);
といったような宣言と比べると、簡潔さ、利用度の高さなどにおいて桁違いに優れているように思います。

最近まで、気づかなかったのですが、C言語では変数の初期化と関数の定義はまったく別物な訳ですが、というのは、変数の初期化では関数呼び出しやfor文などは使えないし、関数の定義は、変数の初期化とは少し書き方が違いますよね...:

int a = 0;//変数の初期化は=を使うけど、
int a(int i){return i;} //関数の定義では=出てこない…

でも、Haskellでは、こんなことができる:

a :: [ [Int] ]
a = [ [1..5], replicate 5 5]--変数の初期化に関数を呼び出してみる。

b :: Int -> Int
b i = i * 5 --関数の定義は変数の初期化とよく似ている。

C/C++で色々書いていると、ほんとにまれなんですが、複雑なデータ構造を構築して初期化しなきゃいけないときがあって、そうゆう関数を書くのはなんだかとっても不毛な気分になったりしてたのです。Haskellではその辺でずいぶんと強力なサポートが得られますね…

一度HMの簡潔さを知ってしまうと、C系の言語の型宣言の冗長さが目に付いちゃいます。コンパイルエラーが何を言ってるか良くわからないときとかありますが、それもテンプレートをいっぱい使ったC++コンパイルエラーと毛色は似ているような気はしますね…

今日はこの辺で。
ではでは。