2
1

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 3 years have passed since last update.

OptionT[Scala with Cats]の説明

Last updated at Posted at 2020-12-29

初めに

OptionTの簡単な説明…OptionT[F[_], A]は、F[Option[A]]の軽量ラッパーです。 OptionFutureなどの型内に配置するような処理をする際、OptionTを使うことによりコードをスッキリまとめやすくなります。

Scala with CatsのOptionTについて公式ドキュメントを自分なりに翻訳して説明していきます!!
※ところどころ、分かりやすいように文を付け加えてます!

まえがき

OptionT[F[_], A]は、F[Option[A]]の軽量ラッパーです。 技術的に言えば、これはOptionのモナド変換子ですが、それが役立つために何を意味するのかを知る必要は無いでしょう。 OptionTは、F[Option[A]]を直接使用するよりも便利です。

mapボイラープレートを減らす

ボイラープレートとは…仕様上省略不能で、かつほとんど変更を加えることなく多くの場所に組み込む必要があるソースコードのこと。[Wikipediaより]

次のシナリオを検討しましょう。

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

val customGreeting: Future[Option[String]] = Future.successful(Some("welcome back, Lola"))

いろいろな形のあいさつをやってみましょう。

val excitedGreeting: Future[Option[String]] = customGreeting.map(_.map(_ + "!"))

val hasWelcome: Future[Option[String]] = customGreeting.map(_.filter(_.contains("welcome")))

val noWelcome: Future[Option[String]] = customGreeting.map(_.filterNot(_.contains("welcome")))

val withFallback: Future[String] = customGreeting.map(_.getOrElse("hello, there!"))

ご覧のとおり、これら全てのバリエーションの実装は非常に似ています。Optionの操作(mapfilterfilterNotgetOrElse)を呼び出したいのですが、OptionFutureにラップされているため、最初にFuturemapする必要があります。

OptionTはこの定型文の一部を削除するのに役立ちます。OptionTOptionのメソッドのように見えるメソッドを公開していますが、Futureの外部のmapを呼び出すため、これを行う必要はありません。

import cats.data.OptionT
import cats.implicits._

val customGreetingT: OptionT[Future, String] = OptionT(customGreeting)

val excitedGreeting: OptionT[Future, String] = customGreetingT.map(_ + "!")

val withWelcome: OptionT[Future, String] = customGreetingT.filter(_.contains("welcome"))

val noWelcome: OptionT[Future, String] = customGreetingT.filterNot(_.contains("welcome"))

val withFallback: Future[String] = customGreetingT.getOrElse("hello, there!")

Option[A]および/またはF[A]からOptionT[F, A]

Option[A]および/またはF[A]があり、それらをOptionT[F, A]にリフトしたい場合があるでしょう。このために、OptionTは2つの便利なメソッド、fromOptionliftFを公開しています。例えば、以下のように使用します。

val greetingFO: Future[Option[String]] = Future.successful(Some("Hello"))

val firstnameF: Future[String] = Future.successful("Jane")

val lastnameO: Option[String] = Some("Doe")

val ot: OptionT[Future, String] = for {
  g <- OptionT(greetingFO)
  f <- OptionT.liftF(firstnameF)
  l <- OptionT.fromOption[Future](lastnameO)
} yield s"$g $f $l"

val result: Future[Option[String]] = ot.value // Future(Some("Hello Jane Doe"))

AからOptionT[F,A]

Aのみがあり、FApplicativeインスタンスがあると仮定して、それをOptionT[F,A]にリフトしたい場合は、pureと同意であるsomeを使用できます。OptionT[F,A]を作成するためのnoneメソッドもあります。これにより、OptionラップされたAの型は実際はNoneです。

val greet: OptionT[Future,String] = OptionT.pure("Hola!")

val greetAlt: OptionT[Future,String] = OptionT.some("Hi!")

val failedGreet: OptionT[Future,String] = OptionT.none

mapを超える

Future[Option[String]]に対して実行する操作は、Future.map呼び出しでOptionメソッドをラップするほど単純ではない場合があります。例えば、カスタムgreetingが存在する場合はそれを使用し、それ以外はデフォルトのFuture[String]greetingに戻りたい場合はどうでしょうか?OptionTがないと、この実装は次のようになります。

val defaultGreeting: Future[String] = Future.successful("hello, there")

val greeting: Future[String] = customGreeting.flatMap(custom =>
  custom.map(Future.successful).getOrElse(defaultGreeting))

OptionTgetOrElseメソッドは、Future[A]ではなく型Aのデフォルト値を使用するため、完全に利用することはできません。しかし、getOrElseFメソッドはまさに私たちが望むものです。

val greeting: Future[String] = customGreetingT.getOrElseF(defaultGreeting)

基になるインスタンスへのアクセス

OptionTインスタンスからF[Option[A]]値(この場合はFuture[Option[String]])を取得する場合は、valueを呼び出すだけです。

val customGreeting: Future[Option[String]] = customGreetingT.value

以上で公式ドキュメントよりScala with CatsのOptionTについて説明終わりです!

ありがとうございました!!🙇‍♂️

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?