catsによるMonadErrorの説明資料です。
.POBE&SSPSXJUIDBUT
View Slide
͢͜ͱw .POBE&SSPSͱw DBUTΛ༻͍ͨ.POBE&SSPSͷ࣮
.POBE&SSPSͱ.POBEͰநԽΛߦ͏ࡍʹɺΤϥʔϋϯυϦϯάΛิॿ͢Δͷ
நԽdef authF(name: String, password: String): Future[User]def authT(name: String, password: String): Try[User]def authE(name: String, password: String): Either[String, User]def auth[F[_]](name: String, password: String): F[User]5BHMFTT'JOBMͰྑ͘ग़ͯ͘Δͭ
ΤϥʔϋϯυϦϯά'VUVSF&JUIFS5SZΤϥʔʹର͢ΔॲཧFuture {???throw new RuntimeException} recoverWith {case e: IllegalArgumentException => Future.successful(0)}Try {???throw new RuntimeException} match {case Success(result) => resultcase Failure(e) => println(s"failure :${e.getMessage}")}Either {???Left("Error")} match {case Right(success) => successcase Left(e) => println(s"failure: $e")}
.POBEͰநԽ͕͍͠ྫ'VUVSF&JUIFS5SZdef program(value: Either[String, Int], e: => String): Either[String, Int] = for {n result else Right(n * 2)} yield resultdef program(value: Future[Int], e: => String)(implicit ec: ExecutionContext): Future[Int] = for {n result else Future.successful(n*2)} yield resultdef program(value: Try[Int], e: => String): Try[Int] = for {n result else Success(n*2)} yield result
'VUVSF&JUIFS5SZdef program(value: Either[String, Int], e: => String): Either[String, Int] = for {n result else Right(n * 2)} yield result.POBEʹΑͬͯΤϥʔϋϯυϦϯά͕ҟͳΔ.POBEͰநԽ͕͍͠ྫdef program(value: Future[Int], e: => String)(implicit ec: ExecutionContext): Future[Int] = for {n result else Future.successful(n*2)} yield resultdef program(value: Try[Int], e: => String): Try[Int] = for {n result else Success(n*2)} yield result
Ϟνϕʔγϣϯdef program[F[_], E](value: F[Int], e: => E)(implicit ME: MonadError[F, E]): F[Int]def program(value: Either[String, Int], e: => String): Either[String, Int]def program(value: Future[Int], e: => String)(implicit ec: ExecutionContext): Future[Int]def program(value: Try[Int], e: => String): Try[Int]
$BUT4DBMB[ͷ෦྾ʹΑͬͯੜ·Εͨؔܕϓϩάϥϛϯά༻ͷ4DBMBϥΠϒϥϦɾࠒੜɾʹWϦϦʔε ݱࡏͷ࠷৽Wɾݍ DBUFHPSZʹ༝དྷ
.POBE&SSPSJODBUTtrait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] {def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A]def raiseError[A](e: E): F[A]def handleError[A](fa: F[A])(f: E => A): F[A]…}.POBEͷܕ 'ʹؚ·ΕΔΤϥʔͷܕ.POBEΛܧঝ
w SBJTF&SSPSw FOTVSFw IBOEMF&SSPS˞.POBEͳͷͰɺQVSFɺNBQɺqBU.BQؚΜͰ͍·͢දతͳϝιου.POBE&SSPSJODBUT
QVSFdef pure[A](x: A): F[A]"Λ'ʹ্࣋ͪ͛Δ.POBEͰ͓ͳ͡Έͷؔdef pure[B](b: B): Either[A, B] = Right(b)'VUVSF&JUIFSdef pure[A](x: A): Future[A] = Future.successful(x)
SBJTF&SSPSΤϥʔͷதΛ'ʹ্࣋ͪ͛Δdef raiseError[A](e: E): F[A]def raiseError[B](e: A): Either[A, B] = Left(e)def raiseError[A](e: Throwable): Future[A] = Future.failed(e)'VUVSF&JUIFS
IBOEMF&SSPSdef handleError[A](fa: F[A])(f: E => A): F[A]ΤϥʔΛͬͯޭʹม͢Δɻ'VUVSFͷSFDPWFS8JUIΈ͍ͨͳͭmonadError.handleError(value) {case failure: E =>"It's Ok"}override def handleError[A](fea: Future[A])(f: Throwable => A): Future[A] =fea.recover { case t => f(t) }'VUVSFdef handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]monadError.handleErrorWith(value) {case failure: E =>monadError.pure("It's Ok")case _ =>monadError.raiseError(failure)}
FOTVSFdef ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A]MonadError[({type E[A] = Either[String, A]})#E, String].ensure(Right(42))("Error")(_ > 0) // Right(42)MonadError[({type E[A] = Either[String, A]})#E, String].ensure(Right(-42))(“Error”)(_ > 0) // Left(Error)def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A] =flatMap(fa)(a => if (predicate(a)) pure(a) else raiseError(error))݅ࣜ QSFEJDBUFΛ͔͚ͯɺUSVFͳΒޭɺGBMTFͳΒΤϥʔ FSSPSΛฦؔ͢
.POBE&SSPSʹΑΔநԽΤϥʔॲཧΛநԽtrait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] {def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A] =flatMap(fa)(a => if (predicate(a)) pure(a) else raiseError(error))}؆ܿͳදݱ͕Մೳdef program(value: Either[String, Int], e: => String): Either[String, Int] = for {n result else Right(n * 2)} yield resultdef program[F[_], E](value: F[Int], e: => E)(implicit monadError: MonadError[F, E]): F[Int] = for {n result else monadError.pure(n * 2)} yield resultdef program[F[_], E](value: F[Int], e: => E)(implicit monadError: MonadError[F, E]): F[Int] =monadError.ensure(value)(e)(_ >= 0).map(_*2)
͏ଆ.POBE&SSPSͷ࣮Λࠩ͠ࠐΉ// MonadErrorͷEitherͷ࣮implicit val monadErrorForEither = new MonadError[Either[String, Int], String] {???}val resEitherSuccess = program[({type E[A] = Either[String, A]})#E, String](43.asRight[String], "Error")// Right(86)val resEitherFailure = program[({type E[A] = Either[String, A]})#E, String](-43.asRight[String], "Error")// Left("Error").POBE&SSPSʹΑΔநԽdef program[F[_], E](value: F[Int], e: => E)(implicit monadError: MonadError[F, E]): F[Int] =monadError.ensure(value)(e)(_ >= 0).map(_*2)
new MonadError[Either[A, ?], A] with Traverse[Either[A, ?]] {def pure[B](b: B): Either[A, B] = Right(b)def flatMap[B, C](fa: Either[A, B])(f: B => Either[A, C]): Either[A, C] =fa.right.flatMap(f)def raiseError[B](e: A): Either[A, B] = Left(e)…}new FutureCoflatMap with MonadError[Future, Throwable] with Monad[Future] with StackSafeMonad[Future] {def pure[A](x: A): Future[A] = Future.successful(x)def flatMap[A, B](fa: Future[A])(f: A => Future[B]): Future[B] = fa.flatMap(f)def raiseError[A](e: Throwable): Future[A] = Future.failed(e)…}'VUVSF&JUIFS5SZ 'VUVSF &JUIFS 0QUJPO *0ͷ࣮͕طʹ͋Δ.POBE&SSPS*OTUBODFJODBUT
ͦΕͧΕͷ.POBE&SSPSͷ࣮Λࠩ͠ࠐΉ͚ͩimport cats.instances.try_._val resTrySuccess = program[Try, Throwable](Success(43), new RuntimeException(“Error"))// = Success(43)val resTryFailure = program[Try, Throwable](Success(-43), new RuntimeException("Error"))// = Failure(RuntimeException("Error"))import cats.instances.future._val resFutureSuccess = program[Future, Throwable](Future(43), new RuntimeException(“Error"))// = onComplete => Success(43)val resFutureFailure = program[Future, Throwable](Future(-43), new RuntimeException(“Error"))// = onComplete => Failure(RuntimeException("Error"))'VUVSF&JUIFS5SZimport cats.syntax.either._import cats.instances.either._val resEitherSuccess = program[({type E[A] = Either[String, A]})#E, String](43.asRight[String], "Error")// Right(86)val resEitherFailure = program[({type E[A] = Either[String, A]})#E, String](-43.asRight[String], "Error")// Left("Error")def program[F[_], E](value: F[Int], e: => E)(implicit ME: MonadError[F, E]): F[Int] =ME.ensure(value)(e)(_ >= 0).map(_*2).POBE&SSPS*OTUBODFJODBUT
·ͱΊ.POBE&SSPS.POBEʹΤϥʔϋϯυϦϯάͷৼΔ͍͕Ճ͞Εͨͷ5BHMFTT'JOBMΛڧԽͯ͘͠ΕΔ͔