Slide 1

Slide 1 text

.POBE&SSPS XJUIDBUT

Slide 2

Slide 2 text

࿩͢͜ͱ w .POBE&SSPSͱ͸ w DBUTΛ༻͍ͨ.POBE&SSPSͷ࣮૷

Slide 3

Slide 3 text

.POBE&SSPSͱ͸ .POBEͰந৅ԽΛߦ͏ࡍʹɺ ΤϥʔϋϯυϦϯάΛิॿ͢Δ΋ͷ

Slide 4

Slide 4 text

ந৅Խ 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Ͱ ྑ͘ग़ͯ͘Δ΍ͭ

Slide 5

Slide 5 text

ΤϥʔϋϯυϦϯά 'VUVSF &JUIFS 5SZ Τϥʔʹର͢Δॲཧ Future { ??? throw new RuntimeException } recoverWith { case e: IllegalArgumentException => Future.successful(0) } Try { ??? throw new RuntimeException } match { case Success(result) => result case Failure(e) => println(s"failure :${e.getMessage}") } Either { ??? Left("Error") } match { case Right(success) => success case Left(e) => println(s"failure: $e") }

Slide 6

Slide 6 text

.POBEͰந৅Խ͕೉͍͠ྫ 'VUVSF &JUIFS 5SZ def program(value: Either[String, Int], e: => String): Either[String, Int] = for { n <- value result <- if(n < 0) Left(e) else Right(n * 2) } yield result def program(value: Future[Int], e: => String)(implicit ec: ExecutionContext): Future[Int] = for { n <- value result <- if(n < 0) Future.failed(new RuntimeException(e)) else Future.successful(n*2) } yield result def program(value: Try[Int], e: => String): Try[Int] = for { n <- value result <- if(n < 0) Failure(new RuntimeException(e)) else Success(n*2) } yield result

Slide 7

Slide 7 text

'VUVSF &JUIFS 5SZ def program(value: Either[String, Int], e: => String): Either[String, Int] = for { n <- value result <- if(n < 0) Left(e) else Right(n * 2) } yield result .POBEʹΑͬͯ ΤϥʔϋϯυϦϯά ͕ҟͳΔ .POBEͰந৅Խ͕೉͍͠ྫ def program(value: Future[Int], e: => String)(implicit ec: ExecutionContext): Future[Int] = for { n <- value result <- if(n < 0) Future.failed(new RuntimeException(e)) else Future.successful(n*2) } yield result def program(value: Try[Int], e: => String): Try[Int] = for { n <- value result <- if(n < 0) Failure(new RuntimeException(e)) else Success(n*2) } yield result

Slide 8

Slide 8 text

Ϟνϕʔγϣϯ 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]

Slide 9

Slide 9 text

࿩͢͜ͱ w .POBE&SSPSͱ͸ w DBUTΛ༻͍ͨ.POBE&SSPSͷ࣮૷

Slide 10

Slide 10 text

$BUT 4DBMB[ͷ಺෦෼྾ʹΑͬͯੜ·Εͨ ؔ਺ܕϓϩάϥϛϯά༻ͷ4DBMBϥΠϒϥϦ ɾ೥ࠒ஀ੜ ɾʹWϦϦʔε ݱࡏͷ࠷৽͸W ɾݍ DBUFHPSZ ʹ༝དྷ

Slide 11

Slide 11 text

.POBE&SSPSJODBUT trait 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Λܧঝ

Slide 12

Slide 12 text

w SBJTF&SSPS w FOTVSF w IBOEMF&SSPS ˞.POBEͳͷͰɺQVSFɺNBQɺqBU.BQ΋ؚΜͰ͍·͢ ୅දతͳϝιου .POBE&SSPSJODBUT

Slide 13

Slide 13 text

QVSF def pure[A](x: A): F[A] "Λ'<">ʹ্࣋ͪ͛Δ.POBEͰ͓ͳ͡Έͷؔ਺ def pure[B](b: B): Either[A, B] = Right(b) 'VUVSF &JUIFS def pure[A](x: A): Future[A] = Future.successful(x)

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

IBOEMF&SSPS def 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) } 'VUVSF def 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) }

Slide 16

Slide 16 text

FOTVSF def 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 Λฦؔ͢਺

Slide 17

Slide 17 text

Ϟνϕʔγϣϯ 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]

Slide 18

Slide 18 text

.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 <- value result <- if(n < 0) Left(e) else Right(n * 2) } yield result def program[F[_], E](value: F[Int], e: => E)(implicit monadError: MonadError[F, E]): F[Int] = for { n <- value result <- if(n < 0) monadError.raiseError(e) else monadError.pure(n * 2) } yield result def program[F[_], E](value: F[Int], e: => E)(implicit monadError: MonadError[F, E]): F[Int] = monadError.ensure(value)(e)(_ >= 0).map(_*2)

Slide 19

Slide 19 text

࢖͏ଆ͸.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)

Slide 20

Slide 20 text

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 &JUIFS 5SZ 'VUVSF &JUIFS 0QUJPO *0ͷ࣮૷͕طʹ͋Δ .POBE&SSPS*OTUBODFJODBUT

Slide 21

Slide 21 text

ͦΕͧΕͷ.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 &JUIFS 5SZ import 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

Slide 22

Slide 22 text

·ͱΊ .POBE&SSPS͸.POBEʹΤϥʔϋϯυϦϯάͷ ৼΔ෣͍͕௥Ճ͞Εͨ΋ͷ 5BHMFTT'JOBMΛڧԽͯ͘͠ΕΔ͔΋