//arrow-core/arrow.core/Either

Either

common sealed class Either<out A, out B>

In day-to-day programming, it is fairly common to find ourselves writing functions that can fail. For instance, querying a service may result in a connection issue, or some unexpected JSON response.

To communicate these errors, it has become common practice to throw exceptions; however, exceptions are not tracked in any way, shape, or form by the compiler. To see what kind of exceptions (if any) a function may throw, we have to dig through the source code. Then, to handle these exceptions, we have to make sure we catch them at the call site. This all becomes even more unwieldy when we try to compose exception-throwing procedures.

import arrow.core.andThen

//sampleStart
val throwsSomeStuff: (Int) -> Double = {x -> x.toDouble()}
val throwsOtherThings: (Double) -> String = {x -> x.toString()}
val moreThrowing: (String) -> List<String> = {x -> listOf(x)}
val magic = throwsSomeStuff.andThen(throwsOtherThings).andThen(moreThrowing)
//sampleEnd
fun main() {
 println ("magic = $magic")
}

Assume we happily throw exceptions in our code. Looking at the types of the functions above, any could throw a number of exceptions – we do not know. When we compose, exceptions from any of the constituent functions can be thrown. Moreover, they may throw the same kind of exception (e.g., IllegalArgumentException) and, thus, it gets tricky tracking exactly where an exception came from.

How then do we communicate an error? By making it explicit in the data type we return.

Either vs Validated

In general, Validated is used to accumulate errors, while Either is used to short-circuit a computation upon the first error. For more information, see the Validated vs Either section of the Validated documentation.

By convention, the right side of an Either is used to hold successful values.

import arrow.core.Either

val right: Either<String, Int> =
//sampleStart
 Either.Right(5)
//sampleEnd
fun main() {
 println(right)
}

import arrow.core.Either

val left: Either<String, Int> = //sampleStart Either.Left(“Something went wrong”) //sampleEnd fun main() { println(left) }


Because `Either` is right-biased, it is possible to define a Monad instance for it.



Since we only ever want the computation to continue in the case of `Right` (as captured by the right-bias nature), we fix the left type parameter and leave the right one free.



So, the map and flatMap methods are right-biased:

{: data-executable='true'}

```kotlin
import arrow.core.Either
import arrow.core.flatMap

//sampleStart
val right: Either<String, Int> = Either.Right(5)
val value = right.flatMap{ Either.Right(it + 1) }
//sampleEnd
fun main() {
 println("value = $value")
}

import arrow.core.Either import arrow.core.flatMap

//sampleStart val left: Either<String, Int> = Either.Left(“Something went wrong”) val value = left.flatMap{ Either.Right(it + 1) } //sampleEnd fun main() { println(“value = $value”) }


##  Using Either instead of exceptions



As a running example, we will have a series of functions that will:



<ul><li>Parse a string into an integer</li><li>Calculate the reciprocal</li><li>Convert the reciprocal into a string</li></ul>



Using exception-throwing code, we could write something like this:

```kotlin
import arrow.core.Either
import arrow.core.flatMap

//sampleStart
fun parse(s: String): Int =
  if (s.matches(Regex("-?[0-9]+"))) s.toInt()
  else throw NumberFormatException("$s is not a valid integer.")

fun reciprocal(i: Int): Double =
  if (i == 0) throw IllegalArgumentException("Cannot take reciprocal of 0.")
  else 1.0 / i

fun stringify(d: Double): String = d.toString()
//sampleEnd

Instead, let’s make the fact that some of our functions can fail explicit in the return type.

import arrow.core.Either
import arrow.core.flatMap
import arrow.core.left
import arrow.core.right

//sampleStart
// Either Style
fun parse(s: String): Either<NumberFormatException, Int> =
  if (s.matches(Regex("-?[0-9]+"))) Either.Right(s.toInt())
  else Either.Left(NumberFormatException("$s is not a valid integer."))

fun reciprocal(i: Int): Either<IllegalArgumentException, Double> =
  if (i == 0) Either.Left(IllegalArgumentException("Cannot take reciprocal of 0."))
  else Either.Right(1.0 / i)

fun stringify(d: Double): String = d.toString()

fun magic(s: String): Either<Exception, String> =
  parse(s).flatMap { reciprocal(it) }.map { stringify(it) }
//sampleEnd

These calls to parse return a Left and Right value

import arrow.core.Either

fun parse(s: String): Either<NumberFormatException, Int> =
  if (s.matches(Regex("-?[0-9]+"))) Either.Right(s.toInt())
  else Either.Left(NumberFormatException("$s is not a valid integer."))

//sampleStart
val notANumber = parse("Not a number")
val number2 = parse("2")
//sampleEnd
fun main() {
 println("notANumber = $notANumber")
 println("number2 = $number2")
}

Now, using combinators like flatMap and map, we can compose our functions together.

import arrow.core.Either
import arrow.core.flatMap

fun parse(s: String): Either<NumberFormatException, Int> =
  if (s.matches(Regex("-?[0-9]+"))) Either.Right(s.toInt())
  else Either.Left(NumberFormatException("$s is not a valid integer."))

fun reciprocal(i: Int): Either<IllegalArgumentException, Double> =
  if (i == 0) Either.Left(IllegalArgumentException("Cannot take reciprocal of 0."))
  else Either.Right(1.0 / i)

fun stringify(d: Double): String = d.toString()

fun magic(s: String): Either<Exception, String> =
  parse(s).flatMap{ reciprocal(it) }.map{ stringify(it) }

//sampleStart
val magic0 = magic("0")
val magic1 = magic("1")
val magicNotANumber = magic("Not a number")
//sampleEnd
fun main() {
 println("magic0 = $magic0")
 println("magic1 = $magic1")
 println("magicNotANumber = $magicNotANumber")
}

In the following exercise, we pattern-match on every case in which the Either returned by magic can be in. Note the when clause in the Left - the compiler will complain if we leave that out because it knows that, given the type Either[Exception, String], there can be inhabitants of Left that are not NumberFormatException or IllegalArgumentException. You should also notice that we are using SmartCast for accessing Left and Right values.

import arrow.core.Either
import arrow.core.flatMap

fun parse(s: String): Either<NumberFormatException, Int> =
  if (s.matches(Regex("-?[0-9]+"))) Either.Right(s.toInt())
  else Either.Left(NumberFormatException("$s is not a valid integer."))

fun reciprocal(i: Int): Either<IllegalArgumentException, Double> =
  if (i == 0) Either.Left(IllegalArgumentException("Cannot take reciprocal of 0."))
  else Either.Right(1.0 / i)

fun stringify(d: Double): String = d.toString()

fun magic(s: String): Either<Exception, String> =
  parse(s).flatMap{ reciprocal(it) }.map{ stringify(it) }

//sampleStart
val x = magic("2")
val value = when(x) {
  is Either.Left -> when (x.value) {
    is NumberFormatException -> "Not a number!"
    is IllegalArgumentException -> "Can't take reciprocal of 0!"
    else -> "Unknown error"
  }
  is Either.Right -> "Got reciprocal: ${x.value}"
}
//sampleEnd
fun main() {
 println("value = $value")
}

Instead of using exceptions as our error value, let’s instead enumerate explicitly the things that can go wrong in our program.

import arrow.core.Either
import arrow.core.flatMap
//sampleStart
// Either with ADT Style

sealed class Error {
  object NotANumber : Error()
  object NoZeroReciprocal : Error()
}

fun parse(s: String): Either<Error, Int> =
  if (s.matches(Regex("-?[0-9]+"))) Either.Right(s.toInt())
  else Either.Left(Error.NotANumber)

fun reciprocal(i: Int): Either<Error, Double> =
  if (i == 0) Either.Left(Error.NoZeroReciprocal)
  else Either.Right(1.0 / i)

fun stringify(d: Double): String = d.toString()

fun magic(s: String): Either<Error, String> =
  parse(s).flatMap{reciprocal(it)}.map{ stringify(it) }
//sampleEnd

For our little module, we enumerate any and all errors that can occur. Then, instead of using exception classes as error values, we use one of the enumerated cases. Now, when we pattern match, we are able to comphrensively handle failure without resulting in an else branch; moreover, since Error is sealed, no outside code can add additional subtypes that we might fail to handle.

import arrow.core.Either
import arrow.core.flatMap

sealed class Error {
 object NotANumber : Error()
 object NoZeroReciprocal : Error()
}

fun parse(s: String): Either<Error, Int> =
  if (s.matches(Regex("-?[0-9]+"))) Either.Right(s.toInt())
  else Either.Left(Error.NotANumber)

fun reciprocal(i: Int): Either<Error, Double> =
  if (i == 0) Either.Left(Error.NoZeroReciprocal)
  else Either.Right(1.0 / i)

fun stringify(d: Double): String = d.toString()

fun magic(s: String): Either<Error, String> =
  parse(s).flatMap{ reciprocal(it) }.map{ stringify(it) }

//sampleStart
val x = magic("2")
val value = when(x) {
  is Either.Left -> when (x.value) {
    is Error.NotANumber -> "Not a number!"
    is Error.NoZeroReciprocal -> "Can't take reciprocal of 0!"
  }
  is Either.Right -> "Got reciprocal: ${x.value}"
}
//sampleEnd
fun main() {
 println("value = $value")
}

Either.catch exceptions

Sometimes you do need to interact with code that can potentially throw exceptions. In such cases, you should mitigate the possibility that an exception can be thrown. You can do so by using the catch function.

Example:

import arrow.core.Either

//sampleStart
fun potentialThrowingCode(): String = throw RuntimeException("Blow up!")

suspend fun makeSureYourLogicDoesNotHaveSideEffects(): Either<Error, String> =
  Either.catch { potentialThrowingCode() }.mapLeft { Error.SpecificError }
//sampleEnd
suspend fun main() {
  println("makeSureYourLogicDoesNotHaveSideEffects().isLeft() = ${makeSureYourLogicDoesNotHaveSideEffects().isLeft()}")
}

sealed class Error {
  object SpecificError : Error()
}

Resolve Either into one type of value

In some cases you can not use Either as a value. For instance, when you need to respond to an HTTP request. To resolve Either into one type of value, you can use the resolve function. In the case of an HTTP endpoint you most often need to return some (framework specific) response object which holds the result of the request. The result can be expected and positive, this is the success flow. Or the result can be expected but negative, this is the error flow. Or the result can be unexpected and negative, in this case an unhandled exception was thrown. In all three cases, you want to use the same kind of response object. But probably you want to respond slightly different in each case. This can be achieved by providing specific functions for the success, error and throwable cases.

Example:

import arrow.core.Either
import arrow.core.flatMap
import arrow.core.left
import arrow.core.right

//sampleStart
suspend fun httpEndpoint(request: String = "Hello?") =
  Either.resolve(
    f = {
      if (request == "Hello?") "HELLO WORLD!".right()
      else Error.SpecificError.left()
    },
    success = { a -> handleSuccess({ a: Any -> log(Level.INFO, "This is a: $a") }, a) },
    error = { e -> handleError({ e: Any -> log(Level.WARN, "This is e: $e") }, e) },
    throwable = { throwable -> handleThrowable({ throwable: Throwable -> log(Level.ERROR, "Log the throwable: $throwable.") }, throwable) },
    unrecoverableState = { _ -> Unit.right() }
  )
//sampleEnd
suspend fun main() {
 println("httpEndpoint().status = ${httpEndpoint().status}")
}

@Suppress("UNUSED_PARAMETER")
suspend fun <A> handleSuccess(log: suspend (a: A) -> Either<Throwable, Unit>, a: A): Either<Throwable, Response> =
  Either.catch {
    Response.Builder(HttpStatus.OK)
      .header(CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON)
      .body(a)
      .build()
  }

@Suppress("UNUSED_PARAMETER")
suspend fun <E> handleError(log: suspend (e: E) -> Either<Throwable, Unit>, e: E): Either<Throwable, Response> =
  createErrorResponse(HttpStatus.NOT_FOUND, ErrorResponse("$ERROR_MESSAGE_PREFIX $e"))

suspend fun handleThrowable(log: suspend (throwable: Throwable) -> Either<Throwable, Unit>, throwable: Throwable): Either<Throwable, Response> =
  log(throwable)
    .flatMap { createErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, ErrorResponse("$THROWABLE_MESSAGE_PREFIX $throwable")) }

suspend fun createErrorResponse(httpStatus: HttpStatus, errorResponse: ErrorResponse): Either<Throwable, Response> =
  Either.catch {
    Response.Builder(httpStatus)
      .header(CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON)
      .body(errorResponse)
      .build()
  }

suspend fun log(level: Level, message: String): Either<Throwable, Unit> =
  Unit.right() // Should implement logging.

enum class HttpStatus(val value: Int) { OK(200), NOT_FOUND(404), INTERNAL_SERVER_ERROR(500) }

class Response private constructor(
  val status: HttpStatus,
  val headers: Map<String, String>,
  val body: Any?
) {

  data class Builder(
    val status: HttpStatus,
    var headers: Map<String, String> = emptyMap(),
    var body: Any? = null
  ) {
    fun header(key: String, value: String) = apply { this.headers = this.headers + mapOf<String, String>(key to value) }
    fun body(body: Any?) = apply { this.body = body }
    fun build() = Response(status, headers, body)
  }
}

val CONTENT_TYPE = "Content-Type"
val CONTENT_TYPE_APPLICATION_JSON = "application/json"
val ERROR_MESSAGE_PREFIX = "An error has occurred. The error is:"
val THROWABLE_MESSAGE_PREFIX = "An exception was thrown. The exception is:"
sealed class Error {
  object SpecificError : Error()
}
data class ErrorResponse(val errorMessage: String)
enum class Level { INFO, WARN, ERROR }

There are far more use cases for the resolve function, the HTTP endpoint example is just one of them.

Syntax

Either can also map over the left value with mapLeft, which is similar to map, but applies on left instances.

import arrow.core.Either

//sampleStart
val r : Either<Int, Int> = Either.Right(7)
val rightMapLeft = r.mapLeft {it + 1}
val l: Either<Int, Int> = Either.Left(7)
val leftMapLeft = l.mapLeft {it + 1}
//sampleEnd
fun main() {
 println("rightMapLeft = $rightMapLeft")
 println("leftMapLeft = $leftMapLeft")
}

Either<A, B> can be transformed to Either<B,A> using the swap() method.

import arrow.core.Either.Left
import arrow.core.Either

//sampleStart
val r: Either<String, Int> = Either.Right(7)
val swapped = r.swap()
//sampleEnd
fun main() {
 println("swapped = $swapped")
}

For using Either’s syntax on arbitrary data types. This will make possible to use the left(), right(), contains(), getOrElse() and getOrHandle() methods:

import arrow.core.right

val right7 =
//sampleStart
  7.right()
//sampleEnd
fun main() {
 println(right7)
}

import arrow.core.left

val leftHello = //sampleStart “hello”.left() //sampleEnd fun main() { println(leftHello) }

import arrow.core.right
import arrow.core.contains

//sampleStart
val x = 7.right()
val contains7 = x.contains(7)
//sampleEnd
fun main() {
 println("contains7 = $contains7")
}

import arrow.core.left import arrow.core.getOrElse

//sampleStart val x = “hello”.left() val getOr7 = x.getOrElse { 7 } //sampleEnd fun main() { println(“getOr7 = $getOr7”) }

import arrow.core.left
import arrow.core.getOrHandle

//sampleStart
val x = "hello".left()
val value = x.getOrHandle { "$it world!" }
//sampleEnd
fun main() {
 println("value = $value")
}

For creating Either instance based on a predicate, use Either.conditionally() method. It will evaluate an expression passed as first parameter, in case the expression evaluates to false it will give an Either.Left<L> build from the second parameter. If the expression evaluates to a true it will take the third parameter and give an Either.Right<R>:

import arrow.core.Either

val value =
//sampleStart
 Either.conditionally(true, { "Error" }, { 42 })
//sampleEnd
fun main() {
 println(value)
}

import arrow.core.Either

val value = //sampleStart Either.conditionally(false, { “Error” }, { 42 }) //sampleEnd fun main() { println(value) }


Another operation is `fold`. This operation will extract the value from the Either, or provide a default if the value is `Left`

{: data-executable='true'}

```kotlin
import arrow.core.Either
import arrow.core.right

//sampleStart
val x : Either<Int, Int> = 7.right()
val fold = x.fold({ 1 }, { it + 3 })
//sampleEnd
fun main() {
 println("fold = $fold")
}

import arrow.core.Either import arrow.core.left

//sampleStart val y : Either<Int, Int> = 7.left() val fold = y.fold({ 1 }, { it + 3 }) //sampleEnd fun main() { println(“fold = $fold”) }


The `getOrHandle()` operation allows the transformation of an `Either.Left` value to a `Either.Right` using the value of `Left`. This can be useful when mapping to a single result type is required like `fold()`, but without the need to handle `Either.Right` case.



As an example, we want to map an `Either<Throwable, Int>` to a proper HTTP status code:

{: data-executable='true'}

```kotlin
import arrow.core.Either
import arrow.core.getOrHandle

//sampleStart
val r: Either<Throwable, Int> = Either.Left(NumberFormatException())
val httpStatusCode = r.getOrHandle {
  when(it) {
    is NumberFormatException -> 400
    else -> 500
  }
}
//sampleEnd
fun main() {
 println("httpStatusCode = $httpStatusCode")
}

The leftIfNull operation transforms a null Either.Right value to the specified Either.Left value. If the value is non-null, the value wrapped into a non-nullable Either.Right is returned (very useful to skip null-check further down the call chain). If the operation is called on an Either.Left, the same Either.Left is returned.

See the examples below:

import arrow.core.Either.Right
import arrow.core.leftIfNull

val value =
//sampleStart
 Right(12).leftIfNull({ -1 })
//sampleEnd
fun main() {
 println(value)
}

import arrow.core.Either.Right import arrow.core.leftIfNull

val value = //sampleStart Right(null).leftIfNull({ -1 }) //sampleEnd fun main() { println(value) }

import arrow.core.Either.Left
import arrow.core.leftIfNull

val value =
//sampleStart
 Left(12).leftIfNull({ -1 })
//sampleEnd
fun main() {
 println(value)
}

Another useful operation when working with null is rightIfNotNull. If the value is null, it will be transformed to the specified Either.Left and, if it’s not null, the type will be wrapped to Either.Right.

Example:

import arrow.core.rightIfNotNull

val value =
//sampleStart
 "value".rightIfNotNull { "left" }
//sampleEnd
fun main() {
 println(value)
}

import arrow.core.rightIfNotNull

val value = //sampleStart null.rightIfNotNull { “left” } //sampleEnd fun main() { println(value) }


The inverse of `rightIfNotNull`, `rightIfNull`. If the value is null it will be transformed to the specified `Either.right` and the type will be `Nothing?`. If the value is not null than it will be transformed to the specified `Either.Left`.



Example:

{: data-executable='true'}

```kotlin
import arrow.core.rightIfNull

val value =
//sampleStart
 "value".rightIfNull { "left" }
//sampleEnd
fun main() {
 println(value)
}

import arrow.core.rightIfNull

val value = //sampleStart null.rightIfNull { “left” } //sampleEnd fun main() { println(value) } ```

Arrow contains Either instances for many useful typeclasses that allows you to use and transform right values. Option does not require a type parameter with the following functions, but it is specifically used for Either.Left

Types

Name Summary
Companion common object Companion
Left common data class Left<out A>(value: A) : Either<A, Nothing>
The left side of the disjoint union, as opposed to the Right side.
Right common data class Right<out B>(value: B) : Either<Nothing, B>
The right side of the disjoint union, as opposed to the Left side.

Functions

Name Summary
all common inline fun all(predicate: (B) -> Boolean): Boolean
bifoldLeft common inline fun <C> bifoldLeft(c: C, f: (C, A) -> C, g: (C, B) -> C): C
bifoldMap common inline fun <C> bifoldMap(MN: Monoid<C>, f: (A) -> C, g: (B) -> C): C
bimap common inline fun <C, D> bimap(leftOperation: (A) -> C, rightOperation: (B) -> D): Either<C, D>
Map over Left and Right of this Either
bitraverse common inline fun <AA, C> bitraverse(fe: (A) -> Iterable<AA>, fa: (B) -> Iterable<C>): List<Either<AA, C»
bitraverseOption common inline fun <AA, C> bitraverseOption(fl: (A) -> Option<AA>, fr: (B) -> Option<C>): Option<Either<AA, C»
bitraverseValidated common inline fun <AA, C, D> bitraverseValidated(fe: (A) -> Validated<AA, C>, fa: (B) -> Validated<AA, D>): Validated<AA, Either<C, D»
exists common inline fun exists(predicate: (B) -> Boolean): Boolean
Returns false if Left or returns the result of the application of the given predicate to the Right value.
findOrNull common inline fun findOrNull(predicate: (B) -> Boolean): B?
fold common inline fun <C> fold(ifLeft: (A) -> C, ifRight: (B) -> C): C
Applies ifLeft if this is a Left or ifRight if this is a Right.
foldLeft common inline fun <C> foldLeft(initial: C, rightOperation: (C, B) -> C): C
foldMap common fun <C> foldMap(MN: Monoid<C>, f: (B) -> C): C
isEmpty common fun isEmpty(): Boolean
isLeft common fun isLeft(): Boolean
isNotEmpty common fun isNotEmpty(): Boolean
isRight common fun isRight(): Boolean
map common inline fun <C> map(f: (B) -> C): Either<A, C>
The given function is applied if this is a Right.
mapLeft common inline fun <C> mapLeft(f: (A) -> C): Either<C, B>
The given function is applied if this is a Left.
orNone common fun orNone(): Option<B>
orNull common fun orNull(): B?
Returns the right value if it exists, otherwise nullExample:kotlin:ank:playground import arrow.core.Either.Left import arrow.core.Either.Right<br>//sampleStart val right = Right(12).orNull() // Result: 12 val left = Left(12).orNull() // Result: null //sampleEnd fun main() { println("right = $right") println("left = $left") }
replicate common fun replicate(n: Int): Either<A, List<B»
swap common fun swap(): Either<B, A>
If this is a Left, then return the left value in Right or vice versa.
tap common inline fun tap(f: (B) -> Unit): Either<A, B>
The given function is applied as a fire and forget effect if this is a Right.
tapLeft common inline fun tapLeft(f: (A) -> Unit): Either<A, B>
The given function is applied as a fire and forget effect if this is a Left.
toString common open override fun toString(): String
toValidated common fun toValidated(): Validated<A, B>
toValidatedNel common fun toValidatedNel(): ValidatedNel<A, B>
traverse common inline fun <C> traverse(fa: (B) -> Iterable<C>): List<Either<A, C»
traverseOption common inline fun <C> traverseOption(fa: (B) -> Option<C>): Option<Either<A, C»
traverseValidated common inline fun <AA, C> traverseValidated(fa: (B) -> Validated<AA, C>): Validated<AA, Either<A, C»
void common fun void(): Either<A, Unit>

Inheritors

Name
Either
Either

Extensions

Name Summary
bind common fun <A> Either<Throwable, A>.bind(): A
bisequence common fun <A, B> Either<Iterable<A>, Iterable<B».bisequence(): List<Either<A, B»
bisequenceOption common fun <A, B> Either<Option<A>, Option<B».bisequenceOption(): Option<Either<A, B»
bisequenceValidated common fun <A, B, C> Either<Validated<A, B>, Validated<A, C».bisequenceValidated(): Validated<A, Either<B, C»
combine common fun <A, B> Either<A, B>.combine(SGA: Semigroup<A>, SGB: Semigroup<B>, b: Either<A, B>): Either<A, B>
combineK common fun <A, B> Either<A, B>.combineK(y: Either<A, B>): Either<A, B>
compareTo common operator fun <A : Comparable<A>, B : Comparable<B» Either<A, B>.compareTo(other: Either<A, B>): Int
contains common fun <A, B> Either<A, B>.contains(elem: B): Boolean
Returns true if this is a Either.Right and its value is equal to elem (as determined by ==), returns false otherwise.
ensure common inline fun <A, B> Either<A, B>.ensure(error: () -> A, predicate: (B) -> Boolean): Either<A, B>
filterOrElse common inline fun <A, B> Either<A, B>.filterOrElse(predicate: (B) -> Boolean, default: () -> A): Either<A, B>
Returns Either.Right with the existing value of Either.Right if this is a Either.Right and the given predicate holds for the right value.
filterOrOther common inline fun <A, B> Either<A, B>.filterOrOther(predicate: (B) -> Boolean, default: (B) -> A): Either<A, B>
Returns Either.Right with the existing value of Either.Right if this is a Either.Right and the given predicate holds for the right value.
flatMap common inline fun <A, B, C> Either<A, B>.flatMap(f: (B) -> Either<A, C>): Either<A, C>
Binds the given function across Either.Right.
flatten common fun <A, B> Either<A, Either<A, B».flatten(): Either<A, B>
getOrElse common inline fun <B> Either<*, B>.getOrElse(default: () -> B): B
Returns the value from this Either.Right or the given argument if this is a Either.Left.
getOrHandle common inline fun <A, B> Either<A, B>.getOrHandle(default: (A) -> B): B
Returns the value from this Either.Right or allows clients to transform Either.Left to Either.Right while providing access to the value of Either.Left.
handleError common inline fun <A, B> Either<A, B>.handleError(f: (A) -> B): Either<A, B>
handleErrorWith common inline fun <A, B, C> Either<A, B>.handleErrorWith(f: (A) -> Either<C, B>): Either<C, B>
Applies the given function f if this is a Left, otherwise returns this if this is a Right.
leftIfNull common inline fun <A, B> Either<A, B?>.leftIfNull(default: () -> A): Either<A, B>
Returns Either.Right with the existing value of Either.Right if this is an Either.Right with a non-null value.
leftWiden common fun <AA, A : AA, B> Either<A, B>.leftWiden(): Either<AA, B>
merge common inline fun <A> Either<A, A>.merge(): A
Returns the value from this Either.Right or Either.Left.
orNull common fun <B> Either<*, B>.orNull(): B?
Returns the value from this Either.Right or null if this is a Either.Left.
redeem common inline fun <A, B, C> Either<A, B>.redeem(fe: (A) -> C, fa: (B) -> C): Either<A, C>
redeemWith common inline fun <A, B, C, D> Either<A, B>.redeemWith(fa: (A) -> Either<C, D>, fb: (B) -> Either<C, D>): Either<C, D>
replicate common fun <A, B> Either<A, B>.replicate(n: Int, MB: Monoid<B>): Either<A, B>
sequence common fun <A, B> Either<A, Iterable<B».sequence(): List<Either<A, B»
sequenceOption common fun <A, B> Either<A, Option<B».sequenceOption(): Option<Either<A, B»
sequenceValidated common fun <A, B, C> Either<A, Validated<B, C».sequenceValidated(): Validated<B, Either<A, C»
widen common fun <A, C, B : C> Either<A, B>.widen(): Either<A, C>
Given B is a sub type of C, re-type this value from Either<A, B> to Either<A, B>kotlin:ank:playground:extension import arrow.core.*<br>fun main(args: Array<String>) { //sampleStart val string: Either<Int, String> = "Hello".left() val chars: Either<Int, CharSequence> = string.widen<Int, CharSequence, String>() //sampleEnd println(chars) }
zip common fun <A, B, C, D> Either<A, B>.zip(fb: Either<A, C>, f: (B, C) -> D): Either<A, D>
fun <A, B, C> Either<A, B>.zip(fb: Either<A, C>): Either<A, Pair<B, C»
inline fun <A, B, C, D, E> Either<A, B>.zip(c: Either<A, C>, d: Either<A, D>, map: (B, C, D) -> E): Either<A, E>
inline fun <A, B, C, D, E, F> Either<A, B>.zip(c: Either<A, C>, d: Either<A, D>, e: Either<A, E>, map: (B, C, D, E) -> F): Either<A, F>
inline fun <A, B, C, D, E, F, G> Either<A, B>.zip(c: Either<A, C>, d: Either<A, D>, e: Either<A, E>, f: Either<A, F>, map: (B, C, D, E, F) -> G): Either<A, G>
inline fun <A, B, C, D, E, F, G, H> Either<A, B>.zip(c: Either<A, C>, d: Either<A, D>, e: Either<A, E>, f: Either<A, F>, g: Either<A, G>, map: (B, C, D, E, F, G) -> H): Either<A, H>
inline fun <A, B, C, D, E, F, G, H, I> Either<A, B>.zip(c: Either<A, C>, d: Either<A, D>, e: Either<A, E>, f: Either<A, F>, g: Either<A, G>, h: Either<A, H>, map: (B, C, D, E, F, G, H) -> I): Either<A, I>
inline fun <A, B, C, D, E, F, G, H, I, J> Either<A, B>.zip(c: Either<A, C>, d: Either<A, D>, e: Either<A, E>, f: Either<A, F>, g: Either<A, G>, h: Either<A, H>, i: Either<A, I>, map: (B, C, D, E, F, G, H, I) -> J): Either<A, J>
inline fun <A, B, C, D, E, F, G, H, I, J, K> Either<A, B>.zip(c: Either<A, C>, d: Either<A, D>, e: Either<A, E>, f: Either<A, F>, g: Either<A, G>, h: Either<A, H>, i: Either<A, I>, j: Either<A, J>, map: (B, C, D, E, F, G, H, I, J) -> K): Either<A, K>
inline fun <A, B, C, D, E, F, G, H, I, J, K, L> Either<A, B>.zip(c: Either<A, C>, d: Either<A, D>, e: Either<A, E>, f: Either<A, F>, g: Either<A, G>, h: Either<A, H>, i: Either<A, I>, j: Either<A, J>, k: Either<A, K>, map: (B, C, D, E, F, G, H, I, J, K) -> L): Either<A, L>

Do you like Arrow?

Arrow Org
<