48
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Scalaの型クラス(typeclass)の分かりやすい説明(Cats公式翻訳)

Last updated at Posted at 2016-08-20

Haskellの型クラスは知っていたけどScalaの型クラスがよくわからなかったのでググッて調べているうちに、CatsというScalaライブラリの公式でとてもコンパクトな説明を見つけました。
自分の理解の助けも兼ねて翻訳しました。

##用語の定義

型クラスはもともと関数型言語の概念なので、オブジェクト指向と同じ言葉でも意味が異なることが多いです。
本文を読む際に注意してください。

用語 意味 本文中の例
データを保持する器。 String
型クラス、クラス ある型に振る舞いを強制する(=特定の関数の引数になれることを保証する)仕組み。オブジェクト指向のクラスとは別物 Show
インスタンス 型クラスによって振る舞いを規定されている型。オブジェクト指向のインスタンスとは別物 Show[String]

##本文

###型クラス

型クラスパターンとは、ある型に新しい振る舞いを与える方法で、Scalaのあらゆるところに顔を出します。こう言うと、Javaで言うところの"インターフェース"みたいなものだと思うかもしれませんね。例を見てみましょう。

/**
 * テキストとして表現する方法を提供する型クラス
 */
trait Show[A] {
  def show(f: A): String
}

この型クラスが言わんとしているのは、Show[A]型の値は、AStringに変換する方法を持っているということです。それでは、AStringに変換する多相的な関数を定義してみます。

def log[A](a: A)(implicit s: Show[A]) = println(s.show(a))

まだShowインスタンスを定義していない状態でlog関数を呼ぼうとすると、コンパイルエラーが出ます。

scala> log("a string")
<console>:15: error: could not find implicit value for parameter s: Show[String]
       log("a string")
          ^

エラーを消すためにStringShowのインスタンスにするのは簡単です。

implicit val stringShow = new Show[String] {
  def show(s: String) = s
}

これで、logの呼び出しが成功しました。

scala> log("a string")
a string

この例は、型クラスパターンの強力さを物語っています。Java.lang.Stringに新しいインターフェースを実装して振る舞いを増やすことはできません。そこで私たちは、既存のJava.lang.Stringを拡張することなしにStringに対するShowの実装を成し遂げたのです。このパターンは、既存の型に新しい振る舞いを組み込めます。このやり方はよく"アドホック多相"と呼ばれます。

ある型に関しては、別の型のShowインスタンスを用意しないとその型のShowインスタンスを作れないこともあります。例として、OptionShowのインスタンスにしてみましょう。

implicit def optionShow[A](implicit sa: Show[A]) = new Show[Option[A]] {
  def show(oa: Option[A]): String = oa match {
    case None => "None"
    case Some(a) => "Some("+ sa.show(a) + ")"
  }
}

こうして、Option[String]Option[Option[String]]に対してlogを適用できるようになりました。

scala> log(Option(Option("hello")))
Some(Some(hello))

Scalaは頻出パターンのための糖衣構文を用意しています。

def log[A: Show](a: A) = println(implicitly[Show[A]].show(a))

これは下のコードと同義です。

def log[A](a: A)(implicit s: Show[A]) = println(s.show(a))

A : Showをパラメータの型に指定すると、暗黙的なパラメータがシグネチャに追加されます(パラメータの名前は私達からはわかりません)。

48
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
48
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?