Last active
October 21, 2016 15:22
-
-
Save cesarjimenez/9d346421305dd5b7ac2ffe5229e5236d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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