LoginSignup
4
3

More than 3 years have passed since last update.

Higher-Kind 型と Natural Transformation を組み合わせて使う

Last updated at Posted at 2019-10-19

最近会社で流行っているやつ。

Scala では Higher-Kind 型Natural Transformation を利用して、
処理の実行モデル(同期、非同期)を抽象化することが可能になるので簡単な実装例を紹介する。

Higher-Kind 型を使う

インターフェイスを定義

インターフェイスの定義に Higher-Kind 型を利用する。

trait HogeRepository[F[_]] {
  def get: F[String]
}

実装する

具体的な実行モデルを指定する。

import scala.util.Try

class HogeRepositoryImpl extends HogeRepository[Try] {
  override def get: Try[String] = Try("Hoge")
}

具体的にする必要がなければ汎用なままでも良いが、必要に応じて MonadApplicative といった制約をつけてやる。

import cats.Monad

class HogeRepositoryImpl2[F[_]: Monad] extends HogeRepository[F] {
  override def get: F[String] = Monad[F].pure("Hoge")
}

利用する

利用側で具体的な型を確定する。

import scala.util.Try

object Main {

  val repository: HogeRepository[Try] = new HogeRepositoryImpl()

  def main(args: Array[String]): Unit = {
    println(repository.get) // Success(Hoge)
  }
}

このあたりは DI でやることが多い。

Natural Transformation を使う

HogeRepository[Try]HogeRepository[Future] とするのにいちいち実装を書き換えたくない。そんなときは Natural Transformation を使う。

F[_]G[_] に変換する仕組みを提供してくれる。

インターフェイスに mapK を実装

import cats.~>

trait HogeRepository[F[_]] {
  self =>
  def get: F[String]
  def mapK[G[_]](nat: F ~> G): HogeRepository[G] = new HogeRepository[G] {
    def get: G[String] = nat(self.get)
  }
}

この F ~ G のところが Natural Transformation

Try ~> Future を実装する

Try ~> Future を実装してそれを mapK にわたすことで HogeRepository[Try] から HogeRepository[Future] を作ることができる。

object Main {

  val tryToFuture: Try ~> Future = new (Try ~> Future) {
    override def apply[A](fa: Try[A]): Future[A] = Future.fromTry(fa)
  }

  val repository: HogeRepository[Future] = new HogeRepositoryImpl().mapK(tryToFuture)

  def main(args: Array[String]): Unit = {
    println(repository.get) // Future(Success(Hoge))
  }
}

おしまい

4
3
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
4
3