Last active
November 12, 2018 16:15
-
-
Save manjuraj/c2d1a340d20678441652 to your computer and use it in GitHub Desktop.
scalaz disjunction
This file contains 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
// | |
// Disjunction - aka Scalaz Either | |
// \/[A, B] is an alternative to Either[A, B] | |
// -\/ is Left (usually represents failure by convention) | |
// \/- is Right (usually represents success by convention) | |
// Left or Right - which side of the Disjunction does the "-" appear? | |
// | |
// Prefer infix notation to express Disjunction Type v: String \/ Double | |
// | |
// References | |
// - http://eed3si9n.com/learning-scalaz/Either.html | |
// | |
// A common use of a disjunction is to explicitly represent the | |
// possibility of failure in a result as opposed to throwing an | |
// exception. By convention, the Left -\/ is used for errors and | |
// the right \/- is reserved for successes. For example, a function | |
// that attempts to parse an integer from a string may have a | |
// return type of \/[NumberFormatException, Int]. However, since | |
// there is no need to actually throw an exception, the type A chosen | |
// for the "left" could be any type representing an error and has | |
// no need to actually extend Exception | |
// | |
// \/[A, B] is isomorphic to scala.Either[A, B], but \/ is | |
// is right-biased, so methods such as `map` and `flatMap` apply | |
// only in the context of the "right" case. This right bias makes | |
// \/ more convenient to use than scala.Either in a monadic | |
// context. Methods such as `swap`, `swapped`, and `leftMap` provide | |
// functionality that `scala.Either` exposes through left projections | |
// | |
// \/[A, B\ is also isomorphic to Validation[A, B]. The subtle but | |
// important difference is that Applicative instances for Validation | |
// accumulates errors ("lefts") while Applicative instances for \/ | |
// "fail fast" on the first "left" they evaluate. This fail-fast | |
// behavior allows \/ to have lawful Monad instances that are consistent | |
// with their Applicative instances, while Validation cannot. | |
// | |
// | |
// Builders: | |
// - using the disjunction singleton instances \/- and -\/ | |
// - left method | |
// - right method | |
// - fromEither method | |
// | |
import scalaz.{ \/, -\/, \/- } | |
scala> \/-("right") | |
res4: scalaz.\/-[String] = \/-(right) | |
scala> -\/("left") | |
res5: scalaz.-\/[String] = -\/(left) | |
scala> \/.right("right") | |
res8: scalaz.\/[Nothing,String] = \/-(right) | |
scala> \/.left("left") | |
res9: scalaz.\/[String,Nothing] = -\/(left | |
// | |
// Isomorphism: Either[A, B] <> \/[A, B] | |
// | |
scala> val e = \/.fromEither(Right("right")) | |
res0: scalaz.\/[Nothing,String] = \/-(right) | |
scala> e.toEither | |
res1: Either[Nothing,String] = Right(right) | |
scala> val e = \/.fromEither(Left("left")) | |
res2: scalaz.\/[String,Nothing] = -\/(left) | |
scala> e.toEither | |
res3: Either[String,Nothing] = Left(left) | |
import scalaz.syntax.std.either._ | |
scala> Left("left").disjunction | |
res1: scalaz.\/[String,B] = -\/(left) | |
scala> Right("right").disjunction | |
res2: scalaz.\/[A,String] = \/-(right) | |
// | |
// Try[A] => \/[Throwable, A] | |
// | |
scala> \/.fromTryCatchNonFatal[Int](throw new RuntimeException("runtime error")) | |
res4: scalaz.\/[Throwable,Int] = -\/(java.lang.RuntimeException: runtime error) | |
scala> \/.fromTryCatchNonFatal[Int](1 / 0) | |
res6: scalaz.\/[Throwable,Int] = -\/(java.lang.ArithmeticException: / by zero) | |
import scalaz._ | |
import scalaz.syntax.either._ | |
scala> "right".right | |
res2: scalaz.\/[Nothing,String] = \/-(right) | |
scala> "left".left | |
res3: scalaz.\/[String,Nothing] = -\/(left) | |
scala> "right".right[Int] | |
res8: scalaz.\/[Int,String] = \/-(right) | |
scala> "left".left[Double] | |
res10: scalaz.\/[String,Double] = -\/(left) | |
scala> for { | |
| a <- "a".right[String] | |
| b <- "b".right[String] | |
| } yield (a, b) | |
res5: scalaz.\/[String,(String, String)] = \/-((a,b)) | |
scala> for { | |
| a <- "a".right[String] | |
| e <- "e".left[Int] | |
| } yield (a, e) | |
res7: scalaz.\/[String,(String, Int)] = -\/(e) | |
scala> for { | |
| a <- "a".right[String] | |
| e <- "e".left[Int] | |
| f <- "f".left[Int] | |
| } yield (a, e, f) | |
res11: scalaz.\/[String,(String, Int, Int)] = -\/(e) | |
import scalaz._ | |
import scalaz.std.either._ | |
// | |
// Option[A] => \/[E, A] | |
// \/>[E] | |
// toRightDisjunction[E](e: => E): E \/ A = o.toRight(self)(e) | |
// | |
// toLeftDisjunction[A] | |
// <\/[A] | |
import scalaz._ | |
import syntax.std.option._ | |
scala> Some(10) \/> "message" | |
res0: scalaz.\/[String,Int] = \/-(10) | |
scala> Some(10).toRightDisjunction("message") | |
res1: scalaz.\/[String,Int] = \/-(10) | |
scala> None \/> "message" | |
res2: scalaz.\/[String,A] = -\/(message) | |
scala> None.toRightDisjunction("message") | |
res3: scalaz.\/[String,A] = -\/(message) | |
scala> Some(10) <\/ "message" | |
res4: scalaz.\/[Int,String] = -\/(10) | |
scala> Some(10).toLeftDisjunction("message") | |
res5: scalaz.\/[Int,String] = -\/(10) | |
scala> None <\/ "message" | |
res6: scalaz.\/[A,String] = \/-(message) | |
scala> None.toLeftDisjunction("message") | |
res7: scalaz.\/[A,String] = \/-(message) | |
import scalaz._ | |
import scalaz.std.list._ | |
import scalaz.syntax.traverse._ | |
import scalaz.syntax.either._ | |
scala> def f(x: Int): \/[String, Int] = if (x > 2) x.right[String] else "failure".left[Int] | |
f: (x: Int)scalaz.\/[String,Int] | |
scala> List(1, 2, 3).traverseU(f) | |
res1: scalaz.\/[String,List[Int]] = -\/(failure) | |
scala> List(3, 4, 5).traverseU(f) | |
res2: scalaz.\/[String,List[Int]] = \/-(List(3, 4, 5)) | |
scala> List(3, 4, 5).map(f).sequenceU | |
res9: scalaz.\/[String,List[Int]] = \/-(List(3, 4, 5)) | |
scala> List(1, 2, 3).map(f).sequenceU | |
res3: scalaz.\/[String,List[Int]] = -\/(failure) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment