arrow.data.Try.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of arrow-data Show documentation
Show all versions of arrow-data Show documentation
Functional Datatypes and abstractions for Kotlin inspired by Cats.
package arrow.data
import arrow.*
import arrow.core.*
import arrow.legacy.*
import arrow.typeclasses.Applicative
typealias Failure = Try.Failure
typealias Success = Try.Success
/**
* The `Try` type represents a computation that may either result in an exception, or return a
* successfully computed value.
*
* Port of https://github.com/scala/scala/blob/v2.12.1/src/library/scala/util/Try.scala
*/
@higherkind
sealed class Try : TryKind {
companion object {
fun pure(a: A): Try = Success(a)
tailrec fun tailRecM(a: A, f: (A) -> TryKind>): Try {
val ev: Try> = f(a).ev()
return when (ev) {
is Failure -> Failure(ev.exception).ev()
is Success -> {
val b: Either = ev.value
when (b) {
is Either.Left -> tailRecM(b.a, f)
is Either.Right -> Success(b.b)
}
}
}
}
inline operator fun invoke(f: () -> A): Try =
try {
Success(f())
} catch (e: Throwable) {
Failure(e)
}
fun raise(e: Throwable): Try = Failure(e)
}
@Deprecated(DeprecatedUnsafeAccess, ReplaceWith("getOrElse { ifEmpty }"))
operator fun invoke() = get()
fun traverse(f: (A) -> HK, GA: Applicative): HK> =
this.ev().fold({ GA.pure(raise(IllegalStateException())) }, { GA.map(f(it), { Try { it } }) })
fun ap(ff: TryKind<(A) -> B>): Try = ff.ev().flatMap { f -> map(f) }.ev()
/**
* Returns the given function applied to the value from this `Success` or returns this if this is a `Failure`.
*/
inline fun flatMap(crossinline f: (A) -> TryKind): Try = fold({ raise(it) }, { f(it).ev() })
/**
* Maps the given function to the value from this `Success` or returns this if this is a `Failure`.
*/
inline fun map(crossinline f: (A) -> B): Try = fold({ Failure(it) }, { Success(f(it)) })
/**
* Converts this to a `Failure` if the predicate is not satisfied.
*/
inline fun filter(crossinline p: Predicate): Try =
fold(
{ Failure(it) },
{ if (p(it)) Success(it) else Failure(TryException.PredicateException("Predicate does not hold for $it")) }
)
/**
* Inverts this `Try`. If this is a `Failure`, returns its exception wrapped in a `Success`.
* If this is a `Success`, returns a `Failure` containing an `UnsupportedOperationException`.
*/
fun failed(): Try =
fold(
{ Success(it) },
{ Failure(TryException.UnsupportedOperationException("Success")) }
)
/**
* Applies `fa` if this is a `Failure` or `fb` if this is a `Success`.
* If `fb` is initially applied and throws an exception,
* then `fa` is applied with this exception.
*/
inline fun fold(fa: (Throwable) -> B, fb: (A) -> B): B =
when (this) {
is Failure -> fa(exception)
is Success -> try {
fb(value)
} catch (e: Throwable) {
fa(e)
}
}
abstract fun isFailure(): Boolean
abstract fun isSuccess(): Boolean
@Deprecated(DeprecatedUnsafeAccess, ReplaceWith("fold({ Unit }, f)"))
fun foreach(f: (A) -> Unit) {
if (isSuccess()) f(get())
}
@Deprecated(DeprecatedUnsafeAccess, ReplaceWith("map { f(it); it }"))
fun onEach(f: (A) -> Unit): Try = map {
f(it)
it
}
fun exists(predicate: Predicate): Boolean = fold({ false }, { predicate(it) })
@Deprecated(DeprecatedUnsafeAccess, ReplaceWith("getOrElse { ifEmpty }"))
abstract fun get(): A
@Deprecated(DeprecatedUnsafeAccess, ReplaceWith("map { body(it); it }"))
fun onSuccess(body: (A) -> Unit): Try {
foreach(body)
return this
}
@Deprecated(DeprecatedUnsafeAccess, ReplaceWith("fold ({ Try { body(it); it }}, { Try.pure(it) })"))
fun onFailure(body: (Throwable) -> Unit): Try = when (this) {
is Success -> this
is Failure -> {
body(exception)
this
}
}
fun toOption(): Option = fold({ None }, { Some(it) })
fun toEither(): Either = fold({ Left(it) }, { Right(it) })
@Deprecated("arrow.data.Either is already right biased. This function will be removed in future releases", ReplaceWith("toEither()"))
fun toDisjunction(): Disjunction = toEither().toDisjunction()
/**
* The `Failure` type represents a computation that result in an exception.
*/
data class Failure(val exception: Throwable) : Try() {
override fun isFailure(): Boolean = true
override fun isSuccess(): Boolean = false
override fun get(): A {
throw exception
}
}
/**
* The `Success` type represents a computation that return a successfully computed value.
*/
data class Success(val value: A) : Try() {
override fun isFailure(): Boolean = false
override fun isSuccess(): Boolean = true
override fun get(): A = value
}
}
sealed class TryException(override val message: String) : kotlin.Exception(message) {
data class PredicateException(override val message: String) : TryException(message)
data class UnsupportedOperationException(override val message: String) : TryException(message)
}
fun Try.foldLeft(b: B, f: (B, A) -> B): B = this.ev().fold({ b }, { f(b, it) })
fun Try.foldRight(lb: Eval, f: (A, Eval) -> Eval): Eval = this.ev().fold({ lb }, { f(it, lb) })
/**
* Returns the value from this `Success` or the given `default` argument if this is a `Failure`.
*
* ''Note:'': This will throw an exception if it is not a success and default throws an exception.
*/
fun Try.getOrDefault(default: () -> B): B = fold({ default() }, { it })
/**
* Returns the value from this `Success` or the given `default` argument if this is a `Failure`.
*
* ''Note:'': This will throw an exception if it is not a success and default throws an exception.
*/
fun Try.getOrElse(default: (Throwable) -> B): B = fold(default, { it })
fun Try.orElse(f: () -> Try): Try = when (this) {
is Try.Success -> this
is Try.Failure -> f()
}
/**
* Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`.
* This is like `flatMap` for the exception.
*/
fun Try.recoverWith(f: (Throwable) -> Try): Try = fold({ f(it) }, { Success(it) })
@Deprecated(DeprecatedAmbiguity, ReplaceWith("recoverWith(f)"))
fun Try.rescue(f: (Throwable) -> Try): Try = recoverWith(f)
/**
* Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`.
* This is like map for the exception.
*/
fun Try.recover(f: (Throwable) -> B): Try = fold({ Success(f(it)) }, { Success(it) })
@Deprecated(DeprecatedAmbiguity, ReplaceWith("recover(f)"))
fun Try.handle(f: (Throwable) -> A): Try = recover(f)
/**
* Completes this `Try` by applying the function `f` to this if this is of type `Failure`,
* or conversely, by applying `s` if this is a `Success`.
*/
fun Try.transform(s: (A) -> Try, f: (Throwable) -> Try): Try = fold({ f(it) }, { flatMap(s) })
fun (() -> A).try_(): Try = Try(this)
fun Try>.flatten(): Try = flatMap(::identity)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy