Skip to content

Instantly share code, notes, and snippets.

@taisukeoe
Last active July 25, 2019 09:41
Show Gist options
  • Save taisukeoe/a23fda864c2b6964e004bada75712807 to your computer and use it in GitHub Desktop.
Save taisukeoe/a23fda864c2b6964e004bada75712807 to your computer and use it in GitHub Desktop.
Reader[Future[X]]をうまく扱うためには、ReaderTでいいと思うよ (248回 rpscalaのフォローアップ)
import cats._
import cats.data.{Kleisli, Reader, ReaderT}
import cats.implicits._
import scala.concurrent.{ExecutionContext, Future}
object ReaderStyle extends App {
def someCalc(i: Int): Int = ???
import ExecutionContext.Implicits.global
val future = Reader { i: Int => Future(someCalc(i)) }
/*
xもyもFuture[Int]型なので、 `+` できない。(コンパイル通らない)。
for {
x <- future
y <- future
} yield x + y
ReaderにはTraverse型クラスのインスタンスがないので、FutureがApplicativeでもsequenceしてFuture[Reader[Int]]を得ることもできない
future.sequence
*/
val futureReaderT = ReaderT { i: Int => Future(someCalc(i)) }
//Reader Monad Transformerを使うと、map / flatMapで中身(この場合はInt)を取り出せる
val composedFutureReaderT = for {
x <- futureReaderT
y <- futureReaderT
} yield x + y
//Reader[Int, Future[Int]のように、applyでIntの値を注入できる
composedFutureReaderT(100)
//ReaderTはただの型エイリアスで、その実態はモナドを作る関数のラッパーであるKleisli
//val futureKleisli = Kleisli { i: Int => Future(someCalc(i)) }
}
@taisukeoe
Copy link
Author

taisukeoe commented Jul 25, 2019

さらにEitherTを積みたい場合はこう?
ReaderTの実態はKleisliなので、他のMonadTransformerに比べると複数積み上げしやすいだろうか。
(Eff案件かな?)

  trait Error

  type EitherTF[T] = EitherT[Future, Error, T]

  /*
   * これと同じこと
   *  val efReaderT: ReaderT[EitherTF, Int, Int] = ReaderT { i: Int => EitherT(Future(someCalc(i).asRight[Error])) }
   */

  val efReaderT: ReaderT[EitherTF, Int, Int] = ReaderT { i: Int => EitherT.rightT[Future,Error](someCalc(i)) }

  val composedReaderTEitherTF = for {
    x <- efReaderT
    y <- efReaderT
  } yield x + y

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment