この記事は、型クラスに興味を持っている人向けです。Haskellや関数型プログラミングの予備知識は必要ありません。JavaやC言語のような静的な型付き言語に慣れていれば、役に立つでしょう。
型クラスとは何かを知っているなら、この項目は飛ばしてください。
要約すると、Haskellの型クラスとは、以下のように定義されます。
これは の制約です。型をOrdのインスタンスにするには、それはEqのインスタンスでなければなりません。
これは関数の定義であり、aをOrdのインスタンスにするために定義するものです。関数の定義は複数存在するかもしれません。
型クラスを得たら、インプットとしてその型クラスのインスタンスだと期待される関数を書くことができます。順序付け演算子を定義してみましょう。
この関数はaを提供する全ての型で機能するように記述します。そのような型は、Ord型クラスのインスタンスです。
Javaのインターフェースを使えば、オブジェクトがサポートするメソッドのセットを記述することができますし、Java 8では、これらのメソッド用のデフォルトでの実装も記述することができます。ですから、Ordと本質的には全く同じインターフェースを書くことができるのです。
これは、JavaのEqインターフェースです。デフォルトの実装を利用しています。どちらか一つをオーバーライドしなければ、メソッドを呼び出そうとする際に無限にループを続けることになります。
これらのインターフェースに関して、ジェネリックなメソッドを書くこともできます。
表面上は、これらはそっくりに見えます。しかし、いくつか重要な違いがあるのです。
この関数の呼び出し元は、Ordのインスタンスであるaならどれでも選ぶことができます。そしてOrderingに戻ります。
忘れないでほしいのは、compareに対するパラメータがいずれも同じ型を持つように型シグネチャが要求するということです! 10と記述してしまうと実行できません。Javaの場合は2つのオブジェクトが何であろうと、Ordインターフェースが実装されていれば引き渡されます。
このメソッドのシグネチャはジェネリックの型変数Aを導き、AによってOrdインターフェースが拡張か実装されなければならないと述べています。このメソッドでは、次に2つのパラメータを取り上げますが、どちらも同じジェネリックA型です。
型クラスはデータ型の定義とクラスのインスタンスに分けられます。ゆえに別のパッケージからToyOrdを取り込むとしたら、以下のようなことが容易にできます。
実行してもうまくいかないHaskellの型クラスを定義してみましょう。
従って、戻り値によって2つの可能性からうまくいく値が選択でき、そうでない場合は全くうまくいきません。
つまり、うまくいく道筋は立てられますが、それはaをパラメータとして扱う場合のみです。
この型変数には2つの構造体があります。1つはJustでジェネリック型a
CanFailの項で幾つかの関数を書くことができます。安全なゼロ除算関数が書けます。
この関数シグネチャはとても面白いことを行なっています。普通の文章に翻訳してみましょう。
上の関数でsafeDivisionのcallerのように、Maybe型を選択することもできます。他のインスタンスは何があるでしょうか。
return型ポリモーフィズムは非常にスマートで、間違いなく型クラスの中で最高のものの1つです。同時に、他の言語でのインターフェースやモジュールとはかけ離れたところにあるものの1つです。