平々毎々(アーカイブ)

はてなダイアリーのアーカイブです。

Re: Scala の implicit parameter は型クラスの一種とはどういうことなのか

Scala の implicit parameter は型クラスの一種とはどういうことなのか - 猫型の蓄音機は 1 分間に 45 回にゃあと鳴くのブックマークコメントに

(続く記事も読みました)C#/Java的に言うと、型クラスは型制約なんですよね。とある型をとある型クラスのインスタンスに「後から」できるかどうかは本質ではないという理解。

と書いたらば、

型制約というだけならば trait でいいじゃないかという話になってしまい、わざわざ型クラスを導入するメリットがないので、やはり既存の型に対する拡張が可能というのは型クラスの本質(の一部)ではないかなぁという理解をわたしはしています。実際型クラスの存在しない C#/Java でも、サブタイピングでの型制約は実現できているわけですし、「なぜわざわざ型クラスを導入する必要があるのか」という視点から見ると、サブタイピングでは実現できない柔軟さを実現する必要があるからかな、と思います。「そうじゃないんだ」「それはこういう理由で本質的には型制約と同等なのだ」という意見があれば是非参考にしたいので教えてください。

という追記がついたので、すこし補足しておきます。

型クラスに対するわたしの理解は、Philip Wadler と Stephen Blottの論文 "How to make ad-hoc polymorphism less ad hoc(PDF)"をベースにした、「パラメトリック多相とアドホック多相の中間」です。
パラメトリック多相はC#/Javaでいうところのジェネリクスですね。一方、アドホック多相はC#/Javaではメソッドや演算子オーバーロードがそれにあたります。この区分はML系言語でもたぶん同じと理解してます(間違ってたら誰かコメントください)。Haskellにはオーバーロードがなく、アドホック多相を実現するには型クラスを使うことになるのですが、型クラスをパラメトリック多相の側から見れば、英語版Wikipediaのように Bounded parametric polymorphism(境界のあるパラメトリック多相) ととらえることもできると理解しています。
で、C#/Javaにとっては、境界のあるパラメトリック多相に該当するのはジェネリクスの型制約しかないわけです。なので、「型クラスは型制約(の仲間)」と言いたかったのですが、ブコメにはカッコの中を書かなかったので、なんだかおかしな主張をしているような感じになってしまいました。HaskellScalaの型クラスが、C#/Javaの型制約と全くイコールだ、と言いたいわけじゃないんです。

C#/Javaの型制約は、継承をベースにしているので、インスタンスメソッドは呼べますが、静的メソッドは呼べません。C#ジェネリクスで、演算子が使えなくてイライラした人も多いのではないでしょうか?(C#ジェネリクスが値型も対象にできるのはいいことなんですが、算術演算に悩んだりとか、ありますよね。)型クラスは型に対して関数が定まる仕組みですから、C#/Javaから見ればむしろ全てが静的メソッドですね。さらに、ある型クラスがほかの型クラスを拡張するという仕組みもあり、そういうのをC#/Javaでシミュレートしようとすると、インスタンスメソッド群を定義したオブジェクトを追加のパラメータとして渡す、いわゆる「貧者の型クラス」にするしかないわけです。そこを暗黙のパラメータを使って、明示的に渡さなくても推論させることができるのがScalaの型クラスです。

と、ここまでなら暗黙の変換はいらないわけですが、「既存の型に対する拡張」ができた方が自由度が高くて便利だし、実際Haskellの型クラスだってinstance宣言を後付けできるわけです(こちらも間違ってたら誰かコメントください)。“Haskellの”型クラスと同じことをScalaでやるには、暗黙の変換を使うという風に理解していますが、それがもしできなかったとしても、継承をベースとした型制約にできないことが型クラスではできる、ということに違いはないのではないでしょうか。

(2016/9追記)けっこう前の記事に今更追記するのもあれなんですが、Olegさんの型クラス解説ページにわかりやすく書かれていますね。型クラス(の実装)は、型に対応づいた関数群であり、この関数群の1インスタンスを渡すことがDictionary Passing、辞書渡し。Haskellの場合はコンパイル時に暗黙的に関数群が渡されるけど、OCamlのように型クラスという機構がない言語ではプログラマーが自分で関数群を渡すしかない。このHaskellにおける「暗黙的に関数群が渡される」をScalaで実現するのがimplicit parameterということで、元記事はそのように述べていましたね。
私は「ワドラーらが論じた一般的な型クラスというものがあって、その一つの特殊例がHaskellの型クラスだ」と言わんばかりの論調でしたが、Haskellの型クラスがむしろ一般的な型クラスの在り方なのかもしれないと思いなおしました。今更ですが、すみませんでした。