Try

Try is a representation of a computation that may or may not fail. Try<A> is a sealed class with two possibles sub-classes—Failure<A>, representing a fail and Success<T> representing a successful operation.

Let's write our division example with Try:

import arrow.data.Try

fun
tryDivide(num: Int, den: Int): Try<Int> = Try { divide(num, den)!! }

 The easiest way to create a Try instance is to use the Try.invoke operator. If the block inside throws an exception, it will return Failure; if everything goes well, Success<Int>, for example, the !! operator will throw NPE if divide returns a null:

fun tryDivision(a: Int, b: Int, den: Int): Try<Tuple2<Int, Int>> {
val aDiv = tryDivide(a, den)
return when (aDiv) {
is Success -> {
val bDiv = tryDivide(b, den)
when (bDiv) {
is Success -> {
Try { aDiv.value toT bDiv.value }
}
is Failure -> Failure(bDiv.exception)
}
}
is Failure -> Failure(aDiv.exception)
}
}

Let's take a look at a short list of the Try<T> functions:

Function

Description

exists(p: Predicate<T>): Boolean

If Success<T> returns p result, on Failure always return false.

filter(p:  Predicate<T>): Try<T>

Returns Success<T> if operation is successful and pass predicate p, otherwise Failure.

<R> flatMap(f: (T) -> Try<R>): Try<R>

flatMap function as in monad.

<R> fold(fa: (Throwable) -> R, fb:(T) -> R): R

Returns value transformed as R, invoking fa if Failure.

getOrDefault(default: () -> T): T

Returns value T, invoking default if Failure.

getOrElse(default: (Throwable) -> T): T

Returns value T, invoking default if Failure.

isFailure(): Boolean

Returns true if Failure, otherwise false.

isSuccess(): Boolean

Returns true if Success, otherwise false.

<R> map(f: (T) -> R): Try<R>

Transforming function as in functor.

onFailure(f: (Throwable) -> Unit): Try<T>

Act on Failure.

onSuccess(f: (T) -> Unit): Try<T>

Act on Success.

orElse(f: () -> Try<T>): Try<T>

Returns itself on Success or f result on Failure.

recover(f: (Throwable) -> T): Try<T>

Transform map function for Failure.

recoverWith(f: (Throwable) -> Try<T>): Try<T>

Transform flatMap function for Failure.

toEither() : Either<Throwable, T>

Transform into EitherFailure to Left<Throwable> and Success<T> to Right<T>.

toOption(): Option<T>

Transform into OptionFailure to None and Success<T> to Some<T>.

 

The flatMap implementation is very similar to Either and Option and shows the value of having a common set of name and behavior conventions:

fun flatMapTryDivision(a: Int, b: Int, den: Int): Try<Tuple2<Int, Int>> {
return tryDivide(a, den).flatMap { aDiv ->
tryDivide(b, den).flatMap { bDiv ->
Try { aDiv toT bDiv }
}
}
}

Monadic comprehensions are available for Try too:

fun comprehensionTryDivision(a: Int, b: Int, den: Int): Try<Tuple2<Int, Int>> {
return Try.monad().binding {
val aDiv = tryDivide(a, den).bind()
val bDiv = tryDivide(b, den).bind()
aDiv toT bDiv
}.ev()
}

There is another kind of monadic comprehension using an instance of MonadError:

fun monadErrorTryDivision(a: Int, b: Int, den: Int): Try<Tuple2<Int, Int>> {
return Try.monadError().bindingCatch {
val aDiv = divide(a, den)!!
val bDiv = divide(b, den)!!
aDiv toT bDiv
}.ev()
}

With monadError.bindingCatch any operation that throws an exception is lifted to Failure, at the end the returns is wrapped into Try<T>. MonadError is also available for Option and Either.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.162.49