OptionT[Scala with Cats]の説明

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

Scala with Catsの`OptionT`について[公式ドキュメント](https://typelevel.org/cats/datatypes/optiont.html)を自分なりに翻訳して説明していきます！！
※ところどころ、分かりやすいように文を付け加えてます！

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

#mapボイラープレートを減らす
<b>ボイラープレート</b>とは…仕様上省略不能で、かつほとんど変更を加えることなく多くの場所に組み込む必要があるソースコードのこと。[[Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%9C%E3%82%A4%E3%83%A9%E3%83%BC%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88)より]

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

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

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

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

```Scala
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`の操作（`map`、`filter`、`filterNot`、`getOrElse`）を呼び出したいのですが、`Option`は`Future`にラップされているため、最初に`Future`に`map`する必要があります。

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

```Scala
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`は２つの便利なメソッド、`fromOption`と`liftF`を公開しています。例えば、以下のように使用します。

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

```Scala
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`がないと、この実装は次のようになります。

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

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

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

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

#基になるインスタンスへのアクセス
`OptionT`インスタンスから`F[Option[A]]`値（この場合は`Future[Option[String]]`）を取得する場合は、`value`を呼び出すだけです。

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

以上で[公式ドキュメント](https://typelevel.org/cats/datatypes/optiont.html)よりScala with CatsのOptionTについて説明終わりです！

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