Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

fuzyco
September 25, 2018

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

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

fuzyco

September 25, 2018
Tweet

More Decks by fuzyco

Other Decks in Technology

Transcript

  1. .POBE&SSPS
    XJUIDBUT

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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")
    }

    View Slide

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

    View Slide

  7. 'VUVSF
    &JUIFS
    5SZ
    def 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 result
    def program(value: Try[Int], e: => String): Try[Int] = for {
    n result else Success(n*2)
    } yield result

    View Slide

  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]

    View Slide

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

    View Slide

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

    ɾݍ DBUFHPSZ
    ʹ༝དྷ

    View Slide

  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Λܧঝ

    View Slide

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

    View Slide

  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)

    View Slide

  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

    View Slide

  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)
    }

    View Slide

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

    View Slide

  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]

    View Slide

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

    View Slide

  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)

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide