Type-classの覚え書き。

`Type-class`パターンの覚え書きです。
使わないと忘れてしまう自分用メモです。

## Type-classを使う前の実装

これだと以下のパターンマッチを使ったコードがあったとして、

```scala
case class User(name: String, age: Int, email: String)

object HTMLSerializerPatternMatch {
  def serialize(value: Any): String = value match {
    case User(name, age, email) => s"<div>${name} (${age} yo) <a href=${email}/> </div>"
    case i: Int =>  s"<div style: color=blue>$value</div>"
}
```

**良くない点が以下**。

* 型安全でない。(Anyを使っている)
* マッチングしたい型が増えたときに、毎回コードの修正が発生する。


上記のコードをType-classを使って改善する。

## Type-classを使った実装

```scala
// 型クラス
trait HTMLSerializer[T] {
  def serialize(value: T): String
}

// 型クラスのコンパニオンオブジェクト
object HTMLSerializer {
  def serialize[T](value: T)(implicit serializer: HTMLSerializer[T]): String =
    serializer.serialize(value)

  def apply[T](implicit serializer: HTMLSerializer[T]) = serializer
}

// 型クラスのインスタンスがInt
implicit object IntSerializer extends HTMLSerializer[Int] {
  override def serialize(value: Int): String = 
    s"<div style: color=blue>$value</div>"
}
// 型クラスのインスタンスが
implicit object UserSerializer extends HTMLSerializer[User] {
  override def serialize(user: User): String = 
    s"<div>${user.name} (${user.age} yo) <a href=${user.email}/> </div>"
}
```

`implicit serializer: HTMLSerializer[T]`の`serializer`に`IntSerializer`もしくは`UserSerializer`が暗黙的に渡される。Stragegyパターンに似たことを`implicit`で表現できる。


```scala
val value1 = User("48hands", 48, "hogehoge@example.com")
val value2 = 48

println(HTMLSerializer.serialize(value1))
println(HTMLSerializer.serialize(value2))
```

## Type-classとimplicit conversion class組み合わせ

以下のようなimplicitなクラスを定義する。
`T`には`User`と`Int`が入ることになる。

```scala
implicit class HTMLEnricher[T](value: T) {
  def toHTML(implicit serializer: HTMLSerializer[T]): String = serializer.serialize(value)
}
```

以下のように利用できる。

```scala
val user = User("48hands", 22, "48hands@example.com")
val number = 48

println(user.toHTML)
println(number.toHTML)
```

実行結果。

```
<div>48hands (22 yo) <a href=48hands@example.com/> </div>
<div style: color=blue>48</div>
```

コード全部のせておきます。

```scala
case class User(name: String, age: Int, email: String)

package object serializer {
  // 型クラス
  trait HTMLSerializer[T] {
    def serialize(value: T): String
  }

  // 型クラスのコンパニオンオブジェクト
  object HTMLSerializer {
    def serialize[T](value: T)(implicit serializer: HTMLSerializer[T]): String =
    serializer.serialize(value)

    def apply[T](implicit serializer: HTMLSerializer[T]) = serializer
  }

  // 型クラスのインスタンス
  implicit object UserSerializer extends HTMLSerializer[User] {
    override def serialize(user: User): String = s"<div>${user.name} (${user.age} yo) <a href=${user.email}/> </div>"
  }

  // 型クラスのインスタンス
  implicit object IntSerializer extends HTMLSerializer[Int] {
    override def serialize(value: Int): String = s"<div style: color=blue>$value</div>"
  }
}

package object richer {
  implicit class HTMLEnricher[T](value: T) {
    import serializer._
    def toHTML(implicit serializer: HTMLSerializer[T]): String = serializer.serialize(value)
  }
}

// エンドポイント
object TypeClassSandbox extends App {
  import richer._

  val user = User("48hands", 22, "48hands@example.com")
  val number = 48

  println(user.toHTML)
  println(number.toHTML)
}
```

(`object HTMLSerializer`はなくても動きます。)