Skip to content

Instantly share code, notes, and snippets.

@cesarjimenez
Last active October 21, 2016 15:22
Show Gist options
  • Save cesarjimenez/9d346421305dd5b7ac2ffe5229e5236d to your computer and use it in GitHub Desktop.
Save cesarjimenez/9d346421305dd5b7ac2ffe5229e5236d to your computer and use it in GitHub Desktop.
import scalaz._
import Scalaz._
/*
* Represents a disjunction: a result that is either an `A` or a `B`.
*
* A common use of a disjunction is to explicitly represent the possibility of failure in a result
* as opposed to throwing an exception (that is a side effect).
*
* `A` [[\/]] `B` is isomorphic to `scala.Either[A, B]`, but [[\/]] is right-biased, so methods such
* as `map` and `flatMap` apply only in the context of the "right" case.
*/
println("=============== EXCEPTIONS CAN BE USED INSIDE DISJUNCTIONS")
val aSuccess = \/.fromTryCatchThrowable[Int, NumberFormatException](
Integer.valueOf("3"))
val anError = \/.fromTryCatchThrowable[Int, NumberFormatException](
Integer.valueOf("CANNOT PARSE"))
anError.isLeft
aSuccess.isLeft
aSuccess.isRight
aSuccess.swap
aSuccess.isLeft
aSuccess.isRight
println("=============== ERROR HANDLING WITHOUT EXCEPTIONS")
sealed trait Error
object CannotConnect extends Error
object GrandmaSmokes extends Error
def isGreaterThan(a: Int, b: Int): Error \/ Int =
if (a > b) a.right
else GrandmaSmokes.left
val error = isGreaterThan(5, 10)
val success = isGreaterThan(8, 2)
isGreaterThan(20, 10) match {
case \/-(success) => s"Everything went OK: $success"
case -\/(error) => "An error occurred"
}
isGreaterThan(20, 10) match {
case DRight(success) => s"Everything went OK: $success"
case DLeft(error) => "An error occurred"
}
println("=============== DISJUNCTION FROM OPTION")
def giveMeAnOption(loaded: Boolean): Option[Int] =
if (loaded) Some(42)
else None
giveMeAnOption(true) \/> "Error occurred"
giveMeAnOption(false) \/> "Error occurred"
giveMeAnOption(true) <\/ "This is a string"
println("=============== GETTING VALUES - You shouldn't be using this often!")
success.getOrElse(42)
error.getOrElse(42)
success.valueOr(error => "There is no value here!")
error.valueOr(error => s"There is no value here!")
println("=============== CHAIN OF ALTERNATIVES")
error orElse success
error ||| success // alias for orElse
println("=============== MAPPING")
error.map(success => "Everything went OK")
error.flatMap(success => "Everything went OK".right)
success.map(success => "Everything went OK")
success.flatMap(success => (success + 5).toString.right)
success.foreach(success => println(s"Success was $success"))
// filter, exists, forall... All of them work with the right part of the disjunction
error.leftMap(error => "An error occurred")
success.leftMap(error => "An error occurred")
success.map(success => 200).leftMap(error => "An error occurred")
success.bimap(error => "An error occurred", success => 200)
error.fold(error => "An error occurred", success => "Everything went OK")
println("=============== TRANSFORMATIONS")
success.toList
success.toOption
error.toOption
success.toEither
success.validation
println("=============== TRAVERSABLE OPERATIONS")
def parseInt(input: String) = \/.fromTryCatchThrowable[Int, NumberFormatException](Integer.valueOf(input))
List("1", "2", "3").traverseU(parseInt)
List("1", "CANNOT PARSE", "3").traverseU(parseInt)
val disjunctionWithOption: Error \/ Option[Int] = Option(5).right
disjunctionWithOption.sequenceU
val disjunctionWithList: Error \/ List[Int] = List(5, 6 ,7).right
disjunctionWithList.sequenceU
println("=============== OPERATIONS WITH SEMIGROUPS")
val x: String \/ Int = 5.right
val y: String \/ Int = 10.right
val oneError: String \/ Int = "I'm an error".left
val anotherError: String \/ Int = " that sometimes happens".left
x +++ y // Both left and right type must be semigroups
x +++ oneError
oneError +++ anotherError
println("=============== APPLICATIVE COMPOSITION - Right type must be Applicative")
(x |@| y) { (x: Int, y: Int) => s"Macaulay says: $x and $y" }
(x |@| oneError) { (x: Int, y: Int) => "This should never be printed!" }
println("=============== SEMIGROUP / MONOID COMPOSITION")
val five: String \/ Int = 5.right
val ten: String \/ Int = 10.right
val noNumber: String \/ Int = "error".left
five |+| ten // Right type must be semigroup
five |+| noNumber
List(five, ten).suml // Right type must be Monoid (suml needs the unit element)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment