Skip to main content

Either

Either / Disjunction

Use Constructor Methods

To create Either type value, instead of doing Right(value) or Left(error), use data constructors provided by FP libraries like Scalaz and Cats.

Using Right() and Left() exposes the data not type.

Right(1)
// res0: Right[Nothing, Int] = Right(value = 1)

Right[String, Int](1)
// res1: Right[String, Int] = Right(value = 1)

Left("Some error")
// res2: Left[String, Nothing] = Left(value = "Some error")

Left[String, Int]("Some error")
// res3: Left[String, Int] = Left(value = "Some error")

// You can List[Either[*, Int]] not List[Right[*, Int]]
List(Right(1), Right(2))
// res4: List[Right[Nothing, Int]] = List(Right(value = 1), Right(value = 2))

So use the constructor methods for Either from Cats or the ones from \/ (Disjunction) from Scalaz.

import cats.syntax.either._

1.asRight[String]
// res6: Either[String, Int] = Right(value = 1)

"Some error".asLeft[Int]
// res7: Either[String, Int] = Left(value = "Some error")

List(1.asRight[String], 2.asRight[String])
// res8: List[Either[String, Int]] = List(Right(value = 1), Right(value = 2))
import cats._

// No
def foo[F[_] : Applicative](n: Int): F[Either[String, Int]] = {
val r = Applicative[F].pure(Right(n))
r
}
// error: type mismatch;
// found : r.type (with underlying type F[scala.util.Right[Nothing,Int]])
// required: F[Either[String,Int]]
// Note: scala.util.Right[Nothing,Int] <: Either[String,Int], but type F is invariant in type _.
// You may wish to define _$$1 as +_$$1 instead. (SLS 4.5)
// r
// ^
import cats._
import cats.syntax.either._

// Yes
def foo[F[_] : Applicative](n: Int): F[Either[String, Int]] = {
val r = Applicative[F].pure(n.asRight[String])
r
}
import cats._

// No
def foo[F[_] : Applicative](n: Int): F[Either[String, Int]] = {
val r = Applicative[F].pure(Left("Some error"))
r
}
// error: type mismatch;
// found : r.type (with underlying type F[scala.util.Left[String,Nothing]])
// required: F[Either[String,Int]]
// Note: scala.util.Left[String,Nothing] <: Either[String,Int], but type F is invariant in type _.
// You may wish to define _$$3 as +_$$3 instead. (SLS 4.5)
// r
// ^
import cats._
import cats.syntax.either._

// Yes
def foo[F[_] : Applicative](n: Int): F[Either[String, Int]] = {
val r = Applicative[F].pure("Some error".asLeft[Int])
r
}