SlideShare ist ein Scribd-Unternehmen logo
1 von 39
Downloaden Sie, um offline zu lesen
Principled Error Handling
Luka Jacobowitz • Scalapeño 2018
Software Developer at
codecentric
Co-organizer of ScalaDus
and IdrisDus
Maintainer of cats,
cats-effect, cats-mtl,
OutWatch
Enthusiastic about FP
About me
Overview
● Error handling with &
without side-effects
● MonadError
● Beyond MonadError
● Conclusions
Simple error handling - Either
def parseUser(s: String): Either[Error, User]
def findByUserId(u: UserId): Either[Error, List[Project]]
for {
user <- parseUser(s)
projects <- findByUserId(user.id)
} yield projects
MonadError
trait MonadError[F[_], E] extends Monad[F] {
def raiseError[A](e: E): F[A]
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]
}
MonadError
trait MonadRaise[F[_], E] extends Monad[F] {
def raiseError[A](e: E): F[A]
}
trait MonadCatch[F[_], E] extends MonadRaise[F, E] {
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]
}
Revisiting Either
def parseUser(s: String): Either[Error, User]
def findByUserId(u: UserId): Either[Error, List[Project]]
for {
user <- parseUser(s)
projects <- findByUserId(user.id)
} yield projects
Abstracting to MonadError
def parseUser[F[_]](s: String)
(implicit F: MonadError[F, Error]): F[User]
def findByUserId[F[_]](u: UserId)
(implicit F: MonadError[F, Error]): F[List[Project]]
for {
user <- parseUser(s)
projects <- findByUserId(user.id)
} yield projects
MonadError - polymorphic programs
def program[F[_], E](value: F[Int], e: => E)
(implicit M: MonadError[F, E]): F[Int] = for {
n <- value
result <- if (n < 0) M.raiseError(e)
else M.pure(n * 2)
} yield result
MonadError - instances
val resEither = program(43.asRight[String], "Error")
val resIO = program(IO.pure(-5), new Throwable())
val resOption = program(Option(21), ())
val resEitherT =
program(EitherT.pure[List, String](9), "Fail!")
val resOptionStateT =
program(StateT.get[Option, Int], ())
MonadError - instances
Three main types of instances:
1. Simple data types like Either, Option or Ior
2. IO-like types, the various cats.effect.IO, monix.eval.Task, but also
scala.concurrent.Future
3. Monad transformers, which get their instances from their
respective underlying monads
MonadError - instances
Three main types of instances:
1. Simple data types like Either, Option or Ior
2. IO-like types, the various cats.effect.IO, monix.eval.Task, but also
scala.concurrent.Future
3. (Monad transformers, which get their instances from their
respective underlying monads)
MonadError - a closer look
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]
If the errors are handled, why does it return the exact same type?
What happens if I return errors in the E => F[A] function?
MonadError - a closer look
def attempt[A](fa: F[A]): F[Either[E, A]]
There is no way the outer F still has any errors, so why does it have the
same type?
Shouldn’t we represent the fact that we handled all the errors in the
type system?
Let’s try better!
We could use two type constructors to represent fallible and
non-fallible types!
trait ErrorControl[F[_], G[_], E] extends MonadRaise[F, E] {
def controlError[A](fa: F[A])(f: E => G[A]): G[A]
}
Let’s try better!
We could use two type constructors to represent fallible and
non-fallible types!
trait ErrorControl[F[_], G[_], E] extends MonadRaise[F, E] {
def monadG: Monad[G]
def controlError[A](fa: F[A])(f: E => G[A]): G[A]
}
ErrorControl - derived functions
def intercept[A](fa: F[A])(f: E => A): G[A]
def trial[A](fa: F[A]): G[Either[E, A]]
def control[A, B](fa: F[A])(f: Either[E, A] => G[B]): G[B]
def trialT[A](fa: F[A]): EitherT[G, E, A]
ErrorControl - laws
a.pure[F].controlError(f) === a.pure[G]
raiseError(e).controlError(f) === f(e)
raiseError(e).flatMap(f) === raiseError(e)
ErrorControl - derived functions
It’d also be nice to lift infallible values in G back into F
def accept[A](ga: G[A]): F[A]
or
def accept: G ~> F
Then we can define things like this:
def absolve[E, A](gea: G[Either[E, A]]): F[A]
def assure[A](ga: G[A])(error: A => Option[E]): F[A]
ErrorControl - homomorphism
accept(x *> y) === accept(x) *> accept(y)
accept(a.pure[G]) === a.pure[F]
accept(ga.flatMap(f)) === accept(ga).flatMap(a => accept(f(a)))
ErrorControl - more laws
controlError(accept(ga))(f) === ga
accept(intercept(fa)(f)) === handleError(fa)(f)
accept(trial(fa)) === attempt(fa)
ErrorControl - instances - Either
implicit def errorControlEither[E] =
new ErrorControl[Either[E, ?], Id, E] {
val monadG = Monad[Id]
def controlError[A](fa: Either[E, A])(f: E => A): A =
fa match {
case Left(e) => f(e)
case Right(a) => a
}
def accept[A](ga: A): Either[E, A] = Right(ga)
}
ErrorControl - instances - IO
What would be the infallible version of IO?
Unexceptional IO, short UIO
UIO is a type with absolutely no errors at all
type IO[A] = UIO[Either[Throwable, A]]
Lives in cats-uio …
ErrorControl - instances - IO
What would be the infallible version of IO?
Unexceptional IO, short UIO
UIO is a type with absolutely no errors at all
type IO[A] = UIO[Either[Throwable, A]]
Lives in cats-uio …for now
ErrorControl - instances - IO
implicit val errorControlIO =
new ErrorControl[IO, UIO, Throwable] {
val monadG = Monad[UIO]
def controlError[A](fa: IO[A])
(f: Throwable => UIO[A]): UIO[A] =
UIO.fromIO(fa.handleErrorWith(f andThen accept))
def accept[A](ga: UIO[A]): IO[A] = UIO.runUIO(ga)
}
ErrorControl - instances - IO
If IO is just UIO[Either[Throwable, A]], then of the three
groups of instances at the beginning only one really
remains.
It all boils down to Either!
ErrorControl - instances - EitherT
implicit def errorControlEitherT[G[_]: Monad, E] =
new ErrorControl[EitherT[G, E, ?], G, E] {
val monadG = Monad[G]
def controlError[A](fa: EitherT[G, E, A])
(f: E => G[A]): G[A] = fa.value.flatMap {
case Left(e) => f(e)
case Right(a) => a.pure[G]
}
def accept[A](ga: G[A]): EitherT[G, E, A] =
EitherT.liftF(ga)
}
ErrorControl - instances - StateT
implicit val errorControlStateT[F[_], G[_], E]
(implicit E: ErrorControl[F, G, E]) =
new ErrorControl[StateT[F, E, ?], StateT[G, E, ?], E] {
val monadG = Monad[StateT[G, E, ?]]
def controlError[A](fa: StateT[F, E, A])
(f: E => StateT[G, E, A]): StateT[G, E, A] =
StateT { s =>
E.controlError(fa.run(s))(e => f(e).run(s)) }
def accept[A](ga: StateT[G, E, A]): StateT[F, E, A] =
ga.mapK(FunctionK.lift(E.accept))
}
ErrorControl - instances - BIO
BIO ???
type BIO[E, A] = UIO[Either[E, A]]
ErrorControl - instances - BIO
implicit val errorControlBIO[E] =
new ErrorControl[BIO[E, ?], BIO[Nothing, ?], E] {
val monadG = Monad[BIO[E, ?]]
def controlError[A](fa: BIO[E, A])
(f: E => BIO[Nothing, A]): BIO[Nothing, A] =
fa.controlError(f)
def accept[A](ga: BIO[Nothing, A]): BIO[E, A] =
ga.leftWiden
}
Is that it?
Caveats
● Working with two type
constructors can be difficult
● Not all errors can be recovered
from
● There might be at least 3
different types of errors.
● We can divide errors into
recoverable/non-recoverable
or retryable/non-retryable or
domain errors
trait ErrorControl[F[_, _]] extends Bifunctor[F] {
def monadThrow[E]: MonadThrow[F[E, ?]]
def controlError[E, A](fea: F[E, A])
(f: E => F[Nothing, A]): F[Nothing, A]
}
This is cool, but requires an adapter for types like IO or Task.
If BIO becomes the new standard, maybe we should revisit this
Alternatives?
Alternatives?
Error handling is really really
really hard
Conclusions
UIO is the primitive type for side-effectful computation
Most asynchronous computations can throw errors though, so it’s not as
wide-spread
Either is the primitive for error handling
It gives us short circuiting on the first error, similar to synchronous
exceptions
Composing them gives us something like ErrorControl
Or something like BIO
Questions?
(there’s so much more to talk about)
Bonus Slides
How to run a bunch of IOs in parallel and accumulate
errors along the way?
type VIO[E, A] = UIO[Validated[E, A]]
def fetch(s: String): VIO[NonEmptySet[Error], User]
list.traverse(fetch)
Bonus Slides
How to support non-fatal errors where no
short-circuiting occurs?
type IOr[E, A] = UIO[Ior[E, A]]
Either does not have to be the primitive for error
handling
Thank you for
listening!
Twitter: @LukaJacobowitz
GitHub: LukaJCB

Weitere ähnliche Inhalte

Was ist angesagt?

Anton Vasiljev: Continuations in Ruby.
Anton Vasiljev: Continuations in Ruby.Anton Vasiljev: Continuations in Ruby.
Anton Vasiljev: Continuations in Ruby.Sphere Consulting Inc
 
Multiple Choice Questions for Java interfaces and exception handling
Multiple Choice Questions for Java interfaces and exception handlingMultiple Choice Questions for Java interfaces and exception handling
Multiple Choice Questions for Java interfaces and exception handlingAbishek Purushothaman
 
SPL 11.1 | Problems on Loop , Nested Loop
SPL 11.1 | Problems on Loop , Nested LoopSPL 11.1 | Problems on Loop , Nested Loop
SPL 11.1 | Problems on Loop , Nested LoopMohammad Imam Hossain
 
Seminar 2 coding_principles
Seminar 2 coding_principlesSeminar 2 coding_principles
Seminar 2 coding_principlesmoduledesign
 
Multiple choice questions for Java io,files and inheritance
Multiple choice questions for Java io,files and inheritanceMultiple choice questions for Java io,files and inheritance
Multiple choice questions for Java io,files and inheritanceAbishek Purushothaman
 
Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverseLuka Jacobowitz
 
Интерфейсы в Python
Интерфейсы в PythonИнтерфейсы в Python
Интерфейсы в PythonAndrew Svetlov
 
Message, Debugging, File Transfer and Type Group
Message, Debugging, File Transfer and Type GroupMessage, Debugging, File Transfer and Type Group
Message, Debugging, File Transfer and Type Groupsapdocs. info
 
Dialog Programming Overview
Dialog Programming OverviewDialog Programming Overview
Dialog Programming Overviewsapdocs. info
 
Relational operators In C language (By: Shujaat Abbas)
Relational operators In C language (By: Shujaat Abbas)Relational operators In C language (By: Shujaat Abbas)
Relational operators In C language (By: Shujaat Abbas)Shujaat Abbas
 
Applet and graphics programming
Applet and graphics programmingApplet and graphics programming
Applet and graphics programmingsrijavel
 
20191116 custom operators in swift
20191116 custom operators in swift20191116 custom operators in swift
20191116 custom operators in swiftChiwon Song
 
My lecture infix-to-postfix
My lecture infix-to-postfixMy lecture infix-to-postfix
My lecture infix-to-postfixSenthil Kumar
 

Was ist angesagt? (17)

Anton Vasiljev: Continuations in Ruby.
Anton Vasiljev: Continuations in Ruby.Anton Vasiljev: Continuations in Ruby.
Anton Vasiljev: Continuations in Ruby.
 
Multiple Choice Questions for Java interfaces and exception handling
Multiple Choice Questions for Java interfaces and exception handlingMultiple Choice Questions for Java interfaces and exception handling
Multiple Choice Questions for Java interfaces and exception handling
 
SPL 11.1 | Problems on Loop , Nested Loop
SPL 11.1 | Problems on Loop , Nested LoopSPL 11.1 | Problems on Loop , Nested Loop
SPL 11.1 | Problems on Loop , Nested Loop
 
Seminar 2 coding_principles
Seminar 2 coding_principlesSeminar 2 coding_principles
Seminar 2 coding_principles
 
Matlab code for secant method
Matlab code for secant methodMatlab code for secant method
Matlab code for secant method
 
Multiple choice questions for Java io,files and inheritance
Multiple choice questions for Java io,files and inheritanceMultiple choice questions for Java io,files and inheritance
Multiple choice questions for Java io,files and inheritance
 
Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverse
 
CST2403 NOTES
CST2403 NOTESCST2403 NOTES
CST2403 NOTES
 
Stack using Array
Stack using ArrayStack using Array
Stack using Array
 
Интерфейсы в Python
Интерфейсы в PythonИнтерфейсы в Python
Интерфейсы в Python
 
Message, Debugging, File Transfer and Type Group
Message, Debugging, File Transfer and Type GroupMessage, Debugging, File Transfer and Type Group
Message, Debugging, File Transfer and Type Group
 
Dialog Programming Overview
Dialog Programming OverviewDialog Programming Overview
Dialog Programming Overview
 
Relational operators In C language (By: Shujaat Abbas)
Relational operators In C language (By: Shujaat Abbas)Relational operators In C language (By: Shujaat Abbas)
Relational operators In C language (By: Shujaat Abbas)
 
Applet and graphics programming
Applet and graphics programmingApplet and graphics programming
Applet and graphics programming
 
Computer instruction set
Computer instruction setComputer instruction set
Computer instruction set
 
20191116 custom operators in swift
20191116 custom operators in swift20191116 custom operators in swift
20191116 custom operators in swift
 
My lecture infix-to-postfix
My lecture infix-to-postfixMy lecture infix-to-postfix
My lecture infix-to-postfix
 

Ähnlich wie Principled Error Handling - Scalapeño

Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FPLuka Jacobowitz
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and EffectsRaymond Roestenburg
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2Hang Zhao
 
Drinking the free kool-aid
Drinking the free kool-aidDrinking the free kool-aid
Drinking the free kool-aidDavid Hoyt
 
Actors and functional_reactive_programming
Actors and functional_reactive_programmingActors and functional_reactive_programming
Actors and functional_reactive_programmingDiego Alonso
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaWiem Zine Elabidine
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patternsTomasz Kowal
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patternsleague
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystifiedAlessandro Lacava
 
Error Handling Without Throwing Exceptions
Error Handling Without Throwing ExceptionsError Handling Without Throwing Exceptions
Error Handling Without Throwing ExceptionsHaeley Yao
 
Erlang bootstrap course
Erlang bootstrap courseErlang bootstrap course
Erlang bootstrap courseMartin Logan
 
Functional IO and Effects
Functional IO and EffectsFunctional IO and Effects
Functional IO and EffectsDylan Forciea
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!Hermann Hueck
 
Scaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazScaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazHeiko Seeberger
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Philip Schwarz
 

Ähnlich wie Principled Error Handling - Scalapeño (20)

Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
 
Zio from Home
Zio from Home Zio from Home
Zio from Home
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and Effects
 
Berlin meetup
Berlin meetupBerlin meetup
Berlin meetup
 
What are monads?
What are monads?What are monads?
What are monads?
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2
 
Drinking the free kool-aid
Drinking the free kool-aidDrinking the free kool-aid
Drinking the free kool-aid
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
Actors and functional_reactive_programming
Actors and functional_reactive_programmingActors and functional_reactive_programming
Actors and functional_reactive_programming
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patterns
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystified
 
Error Handling Without Throwing Exceptions
Error Handling Without Throwing ExceptionsError Handling Without Throwing Exceptions
Error Handling Without Throwing Exceptions
 
Erlang bootstrap course
Erlang bootstrap courseErlang bootstrap course
Erlang bootstrap course
 
Functional IO and Effects
Functional IO and EffectsFunctional IO and Effects
Functional IO and Effects
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 
Scaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazScaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of Scalaz
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'
 

Mehr von Luka Jacobowitz

Monoids, Monoids, Monoids - ScalaLove 2020
Monoids, Monoids, Monoids - ScalaLove 2020Monoids, Monoids, Monoids - ScalaLove 2020
Monoids, Monoids, Monoids - ScalaLove 2020Luka Jacobowitz
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoidsLuka Jacobowitz
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional ProgrammingLuka Jacobowitz
 
Up and Running with the Typelevel Stack
Up and Running with the Typelevel StackUp and Running with the Typelevel Stack
Up and Running with the Typelevel StackLuka Jacobowitz
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeLuka Jacobowitz
 
Traversals for all ocasions
Traversals for all ocasionsTraversals for all ocasions
Traversals for all ocasionsLuka Jacobowitz
 
Building a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLBuilding a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLLuka Jacobowitz
 
What Referential Transparency can do for you
What Referential Transparency can do for youWhat Referential Transparency can do for you
What Referential Transparency can do for youLuka Jacobowitz
 
Reactive Programming in the Browser feat. Scala.js and Rx
Reactive Programming in the Browser feat. Scala.js and RxReactive Programming in the Browser feat. Scala.js and Rx
Reactive Programming in the Browser feat. Scala.js and RxLuka Jacobowitz
 
Reactive Programming in the Browser feat. Scala.js and PureScript
Reactive Programming in the Browser feat. Scala.js and PureScriptReactive Programming in the Browser feat. Scala.js and PureScript
Reactive Programming in the Browser feat. Scala.js and PureScriptLuka Jacobowitz
 

Mehr von Luka Jacobowitz (11)

Monoids, Monoids, Monoids - ScalaLove 2020
Monoids, Monoids, Monoids - ScalaLove 2020Monoids, Monoids, Monoids - ScalaLove 2020
Monoids, Monoids, Monoids - ScalaLove 2020
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoids
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
 
Up and Running with the Typelevel Stack
Up and Running with the Typelevel StackUp and Running with the Typelevel Stack
Up and Running with the Typelevel Stack
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to Free
 
Traversals for all ocasions
Traversals for all ocasionsTraversals for all ocasions
Traversals for all ocasions
 
Building a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLBuilding a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGL
 
What Referential Transparency can do for you
What Referential Transparency can do for youWhat Referential Transparency can do for you
What Referential Transparency can do for you
 
Scala UA 2017
Scala UA 2017Scala UA 2017
Scala UA 2017
 
Reactive Programming in the Browser feat. Scala.js and Rx
Reactive Programming in the Browser feat. Scala.js and RxReactive Programming in the Browser feat. Scala.js and Rx
Reactive Programming in the Browser feat. Scala.js and Rx
 
Reactive Programming in the Browser feat. Scala.js and PureScript
Reactive Programming in the Browser feat. Scala.js and PureScriptReactive Programming in the Browser feat. Scala.js and PureScript
Reactive Programming in the Browser feat. Scala.js and PureScript
 

Kürzlich hochgeladen

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Hararemasabamasaba
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durbanmasabamasaba
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationShrmpro
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsBert Jan Schrijver
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfproinshot.com
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfVishalKumarJha10
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...masabamasaba
 

Kürzlich hochgeladen (20)

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 

Principled Error Handling - Scalapeño

  • 1. Principled Error Handling Luka Jacobowitz • Scalapeño 2018
  • 2. Software Developer at codecentric Co-organizer of ScalaDus and IdrisDus Maintainer of cats, cats-effect, cats-mtl, OutWatch Enthusiastic about FP About me
  • 3. Overview ● Error handling with & without side-effects ● MonadError ● Beyond MonadError ● Conclusions
  • 4. Simple error handling - Either def parseUser(s: String): Either[Error, User] def findByUserId(u: UserId): Either[Error, List[Project]] for { user <- parseUser(s) projects <- findByUserId(user.id) } yield projects
  • 5. MonadError trait MonadError[F[_], E] extends Monad[F] { def raiseError[A](e: E): F[A] def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A] }
  • 6. MonadError trait MonadRaise[F[_], E] extends Monad[F] { def raiseError[A](e: E): F[A] } trait MonadCatch[F[_], E] extends MonadRaise[F, E] { def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A] }
  • 7. Revisiting Either def parseUser(s: String): Either[Error, User] def findByUserId(u: UserId): Either[Error, List[Project]] for { user <- parseUser(s) projects <- findByUserId(user.id) } yield projects
  • 8. Abstracting to MonadError def parseUser[F[_]](s: String) (implicit F: MonadError[F, Error]): F[User] def findByUserId[F[_]](u: UserId) (implicit F: MonadError[F, Error]): F[List[Project]] for { user <- parseUser(s) projects <- findByUserId(user.id) } yield projects
  • 9. MonadError - polymorphic programs def program[F[_], E](value: F[Int], e: => E) (implicit M: MonadError[F, E]): F[Int] = for { n <- value result <- if (n < 0) M.raiseError(e) else M.pure(n * 2) } yield result
  • 10. MonadError - instances val resEither = program(43.asRight[String], "Error") val resIO = program(IO.pure(-5), new Throwable()) val resOption = program(Option(21), ()) val resEitherT = program(EitherT.pure[List, String](9), "Fail!") val resOptionStateT = program(StateT.get[Option, Int], ())
  • 11. MonadError - instances Three main types of instances: 1. Simple data types like Either, Option or Ior 2. IO-like types, the various cats.effect.IO, monix.eval.Task, but also scala.concurrent.Future 3. Monad transformers, which get their instances from their respective underlying monads
  • 12. MonadError - instances Three main types of instances: 1. Simple data types like Either, Option or Ior 2. IO-like types, the various cats.effect.IO, monix.eval.Task, but also scala.concurrent.Future 3. (Monad transformers, which get their instances from their respective underlying monads)
  • 13. MonadError - a closer look def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A] If the errors are handled, why does it return the exact same type? What happens if I return errors in the E => F[A] function?
  • 14. MonadError - a closer look def attempt[A](fa: F[A]): F[Either[E, A]] There is no way the outer F still has any errors, so why does it have the same type? Shouldn’t we represent the fact that we handled all the errors in the type system?
  • 15. Let’s try better! We could use two type constructors to represent fallible and non-fallible types! trait ErrorControl[F[_], G[_], E] extends MonadRaise[F, E] { def controlError[A](fa: F[A])(f: E => G[A]): G[A] }
  • 16. Let’s try better! We could use two type constructors to represent fallible and non-fallible types! trait ErrorControl[F[_], G[_], E] extends MonadRaise[F, E] { def monadG: Monad[G] def controlError[A](fa: F[A])(f: E => G[A]): G[A] }
  • 17. ErrorControl - derived functions def intercept[A](fa: F[A])(f: E => A): G[A] def trial[A](fa: F[A]): G[Either[E, A]] def control[A, B](fa: F[A])(f: Either[E, A] => G[B]): G[B] def trialT[A](fa: F[A]): EitherT[G, E, A]
  • 18. ErrorControl - laws a.pure[F].controlError(f) === a.pure[G] raiseError(e).controlError(f) === f(e) raiseError(e).flatMap(f) === raiseError(e)
  • 19. ErrorControl - derived functions It’d also be nice to lift infallible values in G back into F def accept[A](ga: G[A]): F[A] or def accept: G ~> F Then we can define things like this: def absolve[E, A](gea: G[Either[E, A]]): F[A] def assure[A](ga: G[A])(error: A => Option[E]): F[A]
  • 20. ErrorControl - homomorphism accept(x *> y) === accept(x) *> accept(y) accept(a.pure[G]) === a.pure[F] accept(ga.flatMap(f)) === accept(ga).flatMap(a => accept(f(a)))
  • 21. ErrorControl - more laws controlError(accept(ga))(f) === ga accept(intercept(fa)(f)) === handleError(fa)(f) accept(trial(fa)) === attempt(fa)
  • 22. ErrorControl - instances - Either implicit def errorControlEither[E] = new ErrorControl[Either[E, ?], Id, E] { val monadG = Monad[Id] def controlError[A](fa: Either[E, A])(f: E => A): A = fa match { case Left(e) => f(e) case Right(a) => a } def accept[A](ga: A): Either[E, A] = Right(ga) }
  • 23. ErrorControl - instances - IO What would be the infallible version of IO? Unexceptional IO, short UIO UIO is a type with absolutely no errors at all type IO[A] = UIO[Either[Throwable, A]] Lives in cats-uio …
  • 24. ErrorControl - instances - IO What would be the infallible version of IO? Unexceptional IO, short UIO UIO is a type with absolutely no errors at all type IO[A] = UIO[Either[Throwable, A]] Lives in cats-uio …for now
  • 25. ErrorControl - instances - IO implicit val errorControlIO = new ErrorControl[IO, UIO, Throwable] { val monadG = Monad[UIO] def controlError[A](fa: IO[A]) (f: Throwable => UIO[A]): UIO[A] = UIO.fromIO(fa.handleErrorWith(f andThen accept)) def accept[A](ga: UIO[A]): IO[A] = UIO.runUIO(ga) }
  • 26. ErrorControl - instances - IO If IO is just UIO[Either[Throwable, A]], then of the three groups of instances at the beginning only one really remains. It all boils down to Either!
  • 27. ErrorControl - instances - EitherT implicit def errorControlEitherT[G[_]: Monad, E] = new ErrorControl[EitherT[G, E, ?], G, E] { val monadG = Monad[G] def controlError[A](fa: EitherT[G, E, A]) (f: E => G[A]): G[A] = fa.value.flatMap { case Left(e) => f(e) case Right(a) => a.pure[G] } def accept[A](ga: G[A]): EitherT[G, E, A] = EitherT.liftF(ga) }
  • 28. ErrorControl - instances - StateT implicit val errorControlStateT[F[_], G[_], E] (implicit E: ErrorControl[F, G, E]) = new ErrorControl[StateT[F, E, ?], StateT[G, E, ?], E] { val monadG = Monad[StateT[G, E, ?]] def controlError[A](fa: StateT[F, E, A]) (f: E => StateT[G, E, A]): StateT[G, E, A] = StateT { s => E.controlError(fa.run(s))(e => f(e).run(s)) } def accept[A](ga: StateT[G, E, A]): StateT[F, E, A] = ga.mapK(FunctionK.lift(E.accept)) }
  • 29. ErrorControl - instances - BIO BIO ??? type BIO[E, A] = UIO[Either[E, A]]
  • 30. ErrorControl - instances - BIO implicit val errorControlBIO[E] = new ErrorControl[BIO[E, ?], BIO[Nothing, ?], E] { val monadG = Monad[BIO[E, ?]] def controlError[A](fa: BIO[E, A]) (f: E => BIO[Nothing, A]): BIO[Nothing, A] = fa.controlError(f) def accept[A](ga: BIO[Nothing, A]): BIO[E, A] = ga.leftWiden }
  • 31. Is that it? Caveats ● Working with two type constructors can be difficult ● Not all errors can be recovered from ● There might be at least 3 different types of errors. ● We can divide errors into recoverable/non-recoverable or retryable/non-retryable or domain errors
  • 32. trait ErrorControl[F[_, _]] extends Bifunctor[F] { def monadThrow[E]: MonadThrow[F[E, ?]] def controlError[E, A](fea: F[E, A]) (f: E => F[Nothing, A]): F[Nothing, A] } This is cool, but requires an adapter for types like IO or Task. If BIO becomes the new standard, maybe we should revisit this Alternatives?
  • 34. Error handling is really really really hard
  • 35. Conclusions UIO is the primitive type for side-effectful computation Most asynchronous computations can throw errors though, so it’s not as wide-spread Either is the primitive for error handling It gives us short circuiting on the first error, similar to synchronous exceptions Composing them gives us something like ErrorControl Or something like BIO
  • 36. Questions? (there’s so much more to talk about)
  • 37. Bonus Slides How to run a bunch of IOs in parallel and accumulate errors along the way? type VIO[E, A] = UIO[Validated[E, A]] def fetch(s: String): VIO[NonEmptySet[Error], User] list.traverse(fetch)
  • 38. Bonus Slides How to support non-fatal errors where no short-circuiting occurs? type IOr[E, A] = UIO[Ior[E, A]] Either does not have to be the primitive for error handling
  • 39. Thank you for listening! Twitter: @LukaJacobowitz GitHub: LukaJCB