implicit conversion と type class

第5回 スタートHaskell2という 5 なのか 2 なのかはっきりしろみたいな勉強会があったようです。そこで Haskell と Scala という LT を id:xuwei さんがされたようです。行ってないのでなんともかんともですが…

さて LT のスライドは前述の通り既に公開されているので早速読みました。特に気になった一点について書いてみたいと思います。

implicit は、型クラスのための構文です(キリッ
implicit conversion と implicit parameter という2種類がある
implicit conversion は型クラスには、ほとんど関係ないので忘れてください

ボクが気になったのは最後の行「implicit conversion は型クラスには関係ない」の部分です。

結論からいうと、一応関係はあります。

例えば型 A から型 B への implicit conversion は以下のように定義できます。

class A
class B { def f = 1 }
implicit def aToB(a: A): B = new B

通常 implicit conversion はその名が示すとおり暗黙に適用されるものです。

val af = (new A).f

これは implicit conversion のルールが適用された結果、以下のようなコードになります。

val af = aToB((new A)).f

特に難しいところはないですね。

implicit conversion の定義は、implicit parameter として扱うこともできます。

def af(a: A)(implicit convert: A => B) = convert(a).f

型パラメタを追加して、もう少し generic な定義にしましょう。

def inject[T, U](t: T)(implicit inj: Function1[T, U]) = inj(t)

これはもう Function1 という二つの型変数を取る type class のインスタンスを要求するメソッドにしか見えませんね!

ということで implicit conversion の定義は、ある型からある型への変換を提供する type class のインスタンスの定義として見なせるよ、という話でした。本当はこの後に、実はそういう type class はうまく使うと便利なんだよ、という話を書くつもりだったのですが、カラテが尽きたのでここで終わりです。そこが本題だったんですが…イメージせよ…?

追記:本当はもっと話が続くので inject みたいな定義を書いたんですが、ある rigid な型 A へ変換可能な型制約は以下のように書けます、というかまあ普通はこう書きますよね。

type CanConvertToDouble[T] = T => Double
def tod[T : CanConvertToDouble](t: T)

蛇足なんですが Context Bounds って型パラメタを一つしか取らないものにしか使えないから不便なわけですが、Const みたいなものがあるとすると、

type Const[A] = { type Type[_] = A }

パラメタを取らないもの(T => Double は型変数を含んでいるとはいえ、型コンストラクタではなく型です)は以下のように書けてしまいます。

def tod[T : Const[T => Double]#Type](t: T):Double = implicitly[T => Double].apply(t)

複数パラメタを取るものも、一旦目的の型コンストラクタに適用してしまえばなんのその。

def toseq[T : Const [T => U]#Type, U](t: T, u: U): Seq[U] = Seq(implicitly[T => U].apply(t), u)

非常にどうでもいいですね。