Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize an Either to Right and specify the type of Left?

Tags:

scala

either

I would like to initialize an Either to Left, but this requires specifying the type of the Right side (or vice versa).

If I don't, then the Right side is typed to Nothing by default, and in order to do something such as:

List(5, 42, 7).foldLeft(Left("empty")) {
  case (Left(_), i)  => Right(i)
  case (Right(s), i) => Right(s + i)
}
error: type mismatch;
    found   : scala.util.Right[Nothing,Int]
    required: scala.util.Left[String,Nothing]

I'm obviously forced to verbosely provide the type of both sides of the Either:

List(5, 42, 7).foldLeft(Left("empty"): Either[String, Int]) {
  case (Left(_), i)  => Right(i)
  case (Right(s), i) => Right(s + i)
}

In a similar way, I can use Option.empty[Int] to initialize None as an Option[Int], would there be a way to initialize Left("smthg") as an Either[String, Int]?

like image 707
Xavier Guihot Avatar asked Jun 09 '19 19:06

Xavier Guihot


People also ask

What is right and left in Scala?

Convention dictates that Left is used for failure and Right is used for success. For example, you could use Either[String, Int] to indicate whether a received input is a String or an Int . Since for comprehensions use map and flatMap , the types of function parameters used in the expression must be inferred.

When to use Either Scala?

A common use of Either is as an alternative to Option for dealing with possible missing values. In this usage, scala. None is replaced with a Left which can contain useful information.


2 Answers

Starting Scala 2.13, Left comes with a Left#withRight method which allows upcasting Left[A, Nothing] to Either[A, B]:

Left("smthg").withRight[Int]
// Either[String, Int] = Left("smthg")
Left("smthg")
// Left[String, Nothing] = Left("smthg")

Same goes for the Right side and withLeft:

Right(42).withLeft[String]
// Either[String, Int] = Right(42)

which gives in your case:

List(5, 42, 7).foldLeft(Left("empty").withRight[Int]) {
  case (Left(_),  i) => Right(i)
  case (Right(s), i) => Right(s + i)
}
// Either[String, Int] = Right(54)
like image 67
Xavier Guihot Avatar answered Nov 04 '22 19:11

Xavier Guihot


To supplement Xavier's answer, cats also provide utility methods for creating Either, for example, we can do:

import cats.implicits._

val right = 7.asRight[String] // Either[String, Int]

val left: = "hello cats".asLeft[Int] // Either[String, Int]

It might be useful if in case our project is using scala 2.12 or below.

In case we don't need whole cats library, we can, of course, borrow just extension functions for either:

implicit class EitherIdOps[A](private val obj: A) extends AnyVal {

  /** Wrap a value in `Left`. */
  def asLeft[B]: Either[A, B] = Left(obj)

  /** Wrap a value in `Right`. */
  def asRight[B]: Either[B, A] = Right(obj)

}
like image 40
Krzysztof Atłasik Avatar answered Nov 04 '22 19:11

Krzysztof Atłasik