0Pricing
Scala for Backend Engineering & Functional Programming · レッスン

型クラスパターン

アドホック多相です。

「型クラスパターン」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

型クラスとは

型クラスは、型自体を変更せずに型へ振る舞いを追加するパターンです。これはアドホック多相の一種で、型に基づいてコンパイラーが選択することで、互いに関係のない多くの型に同じ操作を適用できます。

型クラスはHaskellに由来し、CatsなどのScalaライブラリで広く使われています。

解決する問題

継承では、型を定義する時点で振る舞いをその型に組み込む必要があります。しかし、ライブラリにある型など、自分で編集できない型を扱うこともあります。また、コンテキストごとに異なる振る舞いが必要になる場合もあります。型クラスを使えば、振る舞いを外部から付加できます。

ステップ1:トレイトを定義する

型クラスは、型をパラメーターとするtraitです。ここでのShow[A]は、任意のAをStringとしてどのように表示するかを表します。

trait Show[A] {
  def show(value: A): String
}

@main def run(): Unit = {
  println("Show trait defined")
}

ステップ2:インスタンスを提供する

サポートしたい具体的な型ごとに、そのトレイトのinstanceを作成します。これらが型クラスインスタンスです。

trait Show[A] { def show(value: A): String }

object Main {
  val intShow: Show[Int] = (v: Int) => s"Int($v)"
  val strShow: Show[String] = (v: String) => s"Str($v)"

  def main(args: Array[String]): Unit = {
    println(intShow.show(7))
    println(strShow.show("hi"))
  }
}

ステップ3:インスタンスを使う

関数はインスタンスをパラメーターとして受け取ります。Showインスタンスを持つ任意の型に対して、同じrender関数を使用できます。

trait Show[A] { def show(value: A): String }

object Main {
  def render[A](value: A, s: Show[A]): String = s.show(value)

  val intShow: Show[Int] = (v: Int) => s"<$v>"

  def main(args: Array[String]): Unit = {
    println(render(99, intShow))
  }
}

暗黙的にする

インスタンスを手動で渡すのは面倒です。インスタンスとパラメーターにimplicit(Scala 3ではusing)を付けると、コンパイラーが自動的に指定してくれます。

trait Show[A] { def show(value: A): String }

object Main {
  implicit val intShow: Show[Int] = (v: Int) => s"<$v>"

  def render[A](value: A)(implicit s: Show[A]): String = s.show(value)

  def main(args: Array[String]): Unit = {
    println(render(42))
  }
}

アドホック多相

同じ関数名が、引数の型に応じて異なる実装へディスパッチされます。これがアドホック多相であり、サブタイプ多相(継承)やパラメトリック多相(ジェネリクス)とは異なります。

trait Show[A] { def show(value: A): String }

object Main {
  implicit val intShow: Show[Int] = (v: Int) => s"int:$v"
  implicit val boolShow: Show[Boolean] = (v: Boolean) => s"bool:$v"

  def render[A](value: A)(implicit s: Show[A]): String = s.show(value)

  def main(args: Array[String]): Unit = {
    println(render(5))
    println(render(true))
  }
}

カスタム型を扱う

型クラスの真価は、自分で定義した型に振る舞いをきれいに追加できることです。これにより、データクラスをフォーマット処理から分離できます。

trait Show[A] { def show(value: A): String }

case class User(name: String, age: Int)

object Main {
  implicit val userShow: Show[User] = (u: User) => s"${u.name} (${u.age})"

  def render[A](value: A)(implicit s: Show[A]): String = s.show(value)

  def main(args: Array[String]): Unit = {
    println(render(User("Ada", 36)))
  }
}

型クラスとインターフェースの比較

インターフェースは振る舞いを型の定義に結び付けますが、型クラスは両者を分離します。

  • 自分が所有していない型にも型クラスインスタンスを追加できます。
  • コンテキストごとに複数のインスタンスを持てます。
  • 呼び出し箇所でコンパイラーが振る舞いを選択します。

3つの構成要素

すべての型クラスには、次の3つの要素があります。

  • trait(抽象操作)。
  • instances(型ごとの実装)。
  • interface(インスタンスを必要とする関数)。

以降のレッスンで、それぞれを詳しく学びます。

完全なミニ例

暗黙的なインスタンスを使用するジェネリック関数で、このパターンをまとめて確認します。

trait Show[A] { def show(value: A): String }

object Main {
  implicit val intShow: Show[Int] = (v: Int) => s"#$v"
  implicit val strShow: Show[String] = (v: String) => '"' + v + '"'

  def printAll[A](xs: List[A])(implicit s: Show[A]): Unit =
    xs.foreach(x => println(s.show(x)))

  def main(args: Array[String]): Unit = {
    printAll(List(1, 2, 3))
    printAll(List("a", "b"))
  }
}

理解度チェック

型クラスパターンの理解度を確認しましょう。

まとめ

型クラスパターンについて学びました。

  • パラメーター化されたtraitで操作を表します。
  • インスタンスが型ごとの実装を提供します。
  • implicitパラメーターにより、コンパイラーがインスタンスを指定できます。
  • これによりアドホック多相が実現し、自分が所有していない型も拡張できます。

よくある質問

「型クラスパターン」レッスンは無料ですか?

はい。「型クラスパターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

「型クラスパターン」で何を学びますか?

アドホック多相です。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「型クラスパターン」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?

はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 型クラスパターン
  2. インスタンスの定義
  3. よく使う型クラス
  4. 型クラスの導出
← Scala for Backend Engineering & Functional Programmingに戻る