SlideShare una empresa de Scribd logo
1 de 37
Descargar para leer sin conexión
Principled Error Handling
Luka Jacobowitz • LX Scala
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 trial[A](fa: F[A]): G[Either[E, A]]
def intercept[A](fa: F[A])(f: E => A): G[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 errorControlStateT[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
Although you could also say Validated or Ior are THE primitive
Composing them gives us something like ErrorControl
Or something like BIO
Questions?
(there’s so much more to talk about)
Thank you for
listening!
Twitter: @LukaJacobowitz
GitHub: LukaJCB

Más contenido relacionado

La actualidad más candente

One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them AllJohn De Goes
 
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
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type ClassesJohn De Goes
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't FreeKelley Robinson
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)stasimus
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New GameJohn De Goes
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patternsleague
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional SwiftJason Larsen
 
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
 
Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)stasimus
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class PatternsJohn De Goes
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator PatternEric Torreborre
 
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...Philip Schwarz
 
Scala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsScala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsKirill Kozlov
 
Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1Hang Zhao
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monadskenbot
 
Hive function-cheat-sheet
Hive function-cheat-sheetHive function-cheat-sheet
Hive function-cheat-sheetDr. Volkan OBAN
 

La actualidad más candente (20)

One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
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
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't Free
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New Game
 
Hammurabi
HammurabiHammurabi
Hammurabi
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional Swift
 
Map, Reduce and Filter in Swift
Map, Reduce and Filter in SwiftMap, Reduce and Filter in Swift
Map, Reduce and Filter in Swift
 
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
 
Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class Patterns
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
 
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
 
Scala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsScala. Introduction to FP. Monads
Scala. Introduction to FP. Monads
 
Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monads
 
Python : Dictionaries
Python : DictionariesPython : Dictionaries
Python : Dictionaries
 
Hive function-cheat-sheet
Hive function-cheat-sheetHive function-cheat-sheet
Hive function-cheat-sheet
 

Similar a Principled Error Handling with FP

Principled Error Handling - Scalapeño
Principled Error Handling - ScalapeñoPrincipled Error Handling - Scalapeño
Principled Error Handling - ScalapeñoLuka Jacobowitz
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and EffectsRaymond Roestenburg
 
Drinking the free kool-aid
Drinking the free kool-aidDrinking the free kool-aid
Drinking the free kool-aidDavid Hoyt
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adtsHang Zhao
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystifiedAlessandro Lacava
 
Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2Hang Zhao
 
The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)Eric Torreborre
 
Scaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazScaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazHeiko Seeberger
 
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Ruslan Shevchenko
 
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
 
Erlang bootstrap course
Erlang bootstrap courseErlang bootstrap course
Erlang bootstrap courseMartin Logan
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patternsTomasz Kowal
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!Hermann Hueck
 
Monadic Computations in C++14
Monadic Computations in C++14Monadic Computations in C++14
Monadic Computations in C++14Ovidiu Farauanu
 
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with SwiftStanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with SwiftStanfy
 
Monads - Dublin Scala meetup
Monads - Dublin Scala meetupMonads - Dublin Scala meetup
Monads - Dublin Scala meetupMikhail Girkin
 

Similar a Principled Error Handling with FP (20)

Principled Error Handling - Scalapeño
Principled Error Handling - ScalapeñoPrincipled Error Handling - Scalapeño
Principled Error Handling - Scalapeño
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and Effects
 
Zio from Home
Zio from Home Zio from Home
Zio from Home
 
Drinking the free kool-aid
Drinking the free kool-aidDrinking the free kool-aid
Drinking the free kool-aid
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adts
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystified
 
Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2
 
The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)
 
Scaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of ScalazScaladays 2011 - The Ease of Scalaz
Scaladays 2011 - The Ease of Scalaz
 
Berlin meetup
Berlin meetupBerlin meetup
Berlin meetup
 
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
 
Monads do not Compose
Monads do not ComposeMonads do not Compose
Monads do not Compose
 
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
 
Erlang bootstrap course
Erlang bootstrap courseErlang bootstrap course
Erlang bootstrap course
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patterns
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 
Monadic Computations in C++14
Monadic Computations in C++14Monadic Computations in C++14
Monadic Computations in C++14
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with SwiftStanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
 
Monads - Dublin Scala meetup
Monads - Dublin Scala meetupMonads - Dublin Scala meetup
Monads - Dublin Scala meetup
 

Más de Luka 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
 
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
 

Más de Luka Jacobowitz (6)

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

Último

Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionOnePlan Solutions
 
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
 
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
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024Mind IT Systems
 
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
 
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
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfryanfarris8
 

Último (20)

Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
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
 
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 ...
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
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
 
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
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 

Principled Error Handling with FP

  • 1. Principled Error Handling Luka Jacobowitz • LX Scala
  • 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 trial[A](fa: F[A]): G[Either[E, A]] def intercept[A](fa: F[A])(f: E => A): G[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 errorControlStateT[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 Although you could also say Validated or Ior are THE primitive Composing them gives us something like ErrorControl Or something like BIO
  • 36. Questions? (there’s so much more to talk about)
  • 37. Thank you for listening! Twitter: @LukaJacobowitz GitHub: LukaJCB