Monad Error with Cats/monad-error-with-cats

Ca4df28501e4c9cfbceb91f367afa784?s=47 fuzyco
September 25, 2018

Monad Error with Cats/monad-error-with-cats

catsによるMonadErrorの説明資料です。

Ca4df28501e4c9cfbceb91f367afa784?s=128

fuzyco

September 25, 2018
Tweet

Transcript

  1. .POBE&SSPS XJUIDBUT 

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

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

  4. ந৅Խ 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Ͱ ྑ͘ग़ͯ͘Δ΍ͭ
  5. ΤϥʔϋϯυϦϯά '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") }
  6. .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
  7. '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
  8. Ϟνϕʔγϣϯ 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]
  9. ࿩͢͜ͱ w .POBE&SSPSͱ͸ w DBUTΛ༻͍ͨ.POBE&SSPSͷ࣮૷

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

  11. .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Λܧঝ
  12. w SBJTF&SSPS w FOTVSF w IBOEMF&SSPS ˞.POBEͳͷͰɺQVSFɺNBQɺqBU.BQ΋ؚΜͰ͍·͢ ୅දతͳϝιου .POBE&SSPSJODBUT

  13. 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)
  14. 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
  15. 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) }
  16. 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 Λฦؔ͢਺
  17. Ϟνϕʔγϣϯ 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]
  18. .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)
  19. ࢖͏ଆ͸.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)
  20. 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
  21. ͦΕͧΕͷ.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
  22. ·ͱΊ .POBE&SSPS͸.POBEʹΤϥʔϋϯυϦϯάͷ ৼΔ෣͍͕௥Ճ͞Εͨ΋ͷ 5BHMFTT'JOBMΛڧԽͯ͘͠ΕΔ͔΋