Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify recover, and catch APIs. Add getOrElse #2954

Merged
merged 7 commits into from Mar 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 11 additions & 25 deletions arrow-libs/core/arrow-core/api/arrow-core.api

Large diffs are not rendered by default.

Expand Up @@ -2,6 +2,8 @@
package arrow.core

import arrow.core.Either.Right
import arrow.core.raise.EagerEffect
import arrow.core.raise.Effect
import arrow.core.raise.OptionRaise
import arrow.core.raise.option
import arrow.typeclasses.Monoid
Expand Down Expand Up @@ -1271,6 +1273,12 @@ public infix fun <T> Option<T>.or(value: Option<T>): Option<T> = if (isEmpty())

public fun <T> T?.toOption(): Option<T> = this?.let { Some(it) } ?: None

/** Run the [Effect] by returning [Option] of [A], or [None] if raised with [None]. */
public suspend fun <A> Effect<None, A>.toOption(): Option<A> = option { invoke() }

/** Run the [EagerEffect] by returning [Option] of [A], or [None] if raised with [None]. */
public fun <A> EagerEffect<None, A>.toOption(): Option<A> = option { invoke() }

@Deprecated(
NicheAPI + "Prefer using if-else statement",
ReplaceWith(
Expand Down
Expand Up @@ -23,10 +23,8 @@ import kotlin.jvm.JvmInline
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName

public inline fun <E, A> either(@BuilderInference block: Raise<E>.() -> A): Either<E, A> {
contract { callsInPlace(block, EXACTLY_ONCE) }
return fold({ block.invoke(this) }, { Either.Left(it) }, { Either.Right(it) })
}
public inline fun <E, A> either(@BuilderInference block: Raise<E>.() -> A): Either<E, A> =
fold({ block.invoke(this) }, { Either.Left(it) }, { Either.Right(it) })

public inline fun <A> nullable(block: NullableRaise.() -> A): A? {
contract { callsInPlace(block, EXACTLY_ONCE) }
Expand Down Expand Up @@ -61,7 +59,7 @@ public value class NullableRaise(private val cont: Raise<Null>) : Raise<Null> {
@RaiseDSL
public fun ensure(value: Boolean): Unit = ensure(value) { null }
override fun raise(r: Nothing?): Nothing = cont.raise(r)
public fun <B> Option<B>.bind(): B = bind { raise(null) }
public fun <B> Option<B>.bind(): B = getOrElse { raise(null) }

public fun <B> B?.bind(): B {
contract { returns() implies (this@bind != null) }
Expand All @@ -83,7 +81,7 @@ public value class ResultRaise(private val cont: Raise<Throwable>) : Raise<Throw
@JvmInline
public value class OptionRaise(private val cont: Raise<None>) : Raise<None> {
override fun raise(r: None): Nothing = cont.raise(r)
public fun <B> Option<B>.bind(): B = bind { raise(None) }
public fun <B> Option<B>.bind(): B = getOrElse { raise(None) }
public fun ensure(value: Boolean): Unit = ensure(value) { None }

public fun <B> ensureNotNull(value: B?): B {
Expand Down
Expand Up @@ -3,6 +3,7 @@
@file:OptIn(ExperimentalTypeInference::class)
package arrow.core.raise

import arrow.core.identity
import kotlin.experimental.ExperimentalTypeInference
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
Expand Down Expand Up @@ -673,3 +674,12 @@ public inline fun <R, A> effect(@BuilderInference noinline block: suspend Raise<
public typealias EagerEffect<R, A> = Raise<R>.() -> A

public inline fun <R, A> eagerEffect(@BuilderInference noinline block: Raise<R>.() -> A): EagerEffect<R, A> = block

public suspend fun <A> Effect<A, A>.merge(): A = getOrElse(::identity)
public fun <A> EagerEffect<A, A>.merge(): A = getOrElse(::identity)

@Suppress("IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION")
public suspend fun <A> Effect<Nothing, A>.get(): A = getOrElse(::identity)

@Suppress("IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION")
public fun <A> EagerEffect<Nothing, A>.get(): A = getOrElse(::identity)
Expand Up @@ -108,3 +108,9 @@ public inline infix fun <reified T : Throwable, E, A> EagerEffect<E, A>.catch(
@BuilderInference crossinline recover: Raise<E>.(T) -> A,
): EagerEffect<E, A> =
eagerEffect { catch { t: Throwable -> if (t is T) recover(t) else throw t } }

public suspend inline infix fun <E, A> Effect<E, A>.getOrElse(onRaise: (E) -> A): A =
recover({ invoke() }, onRaise)

public inline infix fun <E, A> EagerEffect<E, A>.getOrElse(onRaise: (E) -> A): A =
recover({ invoke() }, onRaise)
Expand Up @@ -90,7 +90,6 @@ public inline fun <R, A, B> fold(
transform: (value: A) -> B,
): B {
contract {
callsInPlace(program, EXACTLY_ONCE)
callsInPlace(error, AT_MOST_ONCE)
callsInPlace(recover, AT_MOST_ONCE)
callsInPlace(transform, AT_MOST_ONCE)
Expand Down
Expand Up @@ -4,11 +4,9 @@ package arrow.core.raise

import arrow.core.Either
import arrow.core.Ior
import arrow.core.None
import arrow.core.Option
import arrow.core.Some
import arrow.core.Validated
import arrow.core.identity
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName

Expand All @@ -24,18 +22,28 @@ public fun <E, A> EagerEffect<E, A>.toValidated(): Validated<E, A> = fold({ Vali
public suspend fun <E, A> Effect<E, A>.toIor(): Ior<E, A> = fold({ Ior.Left(it) }) { Ior.Right(it) }
public fun <E, A> EagerEffect<E, A>.toIor(): Ior<E, A> = fold({ Ior.Left(it) }) { Ior.Right(it) }

@Deprecated(
"orNull is being renamed to getOrNull to be more consistent with the Kotlin Standard Library naming",
ReplaceWith("getOrNull()", "arrow.core.raise.getOrNull")
)
public suspend fun <E, A> Effect<E, A>.orNull(): A? = getOrElse { null }

@Deprecated(
"orNull is being renamed to getOrNull to be more consistent with the Kotlin Standard Library naming",
ReplaceWith("getOrNull()", "arrow.core.raise.getOrNull")
)
public fun <E, A> EagerEffect<E, A>.orNull(): A? = getOrElse { null }

/** Run the [Effect] by returning [A], or `null` if raised with [E]. */
public suspend fun <E, A> Effect<E, A>.orNull(): A? = fold({ _: E -> null }) { it }
public fun <E, A> EagerEffect<E, A>.orNull(): A? = fold({ _: E -> null }) { it }
public suspend fun <E, A> Effect<E, A>.getOrNull(): A? = getOrElse { null }

/** Run the [EagerEffect] by returning [A], or `null` if raised with [E]. */
public fun <E, A> EagerEffect<E, A>.getOrNull(): A? = getOrElse { null }

/** Run the [Effect] by returning [Option] of [A], [orElse] run the fallback lambda and returning its result of [Option] of [A]. */
public suspend fun <E, A> Effect<E, A>.toOption(orElse: suspend (E) -> Option<A>): Option<A> = fold(orElse) { Some(it) }
public inline fun <E, A> EagerEffect<E, A>.toOption(orElse: (E) -> Option<A>): Option<A> = fold(orElse) { Some(it) }

/** Run the [Effect] by returning [Option] of [A], or [None] if raised with [None]. */
public suspend fun <A> Effect<None, A>.toOption(): Option<A> = option { invoke() }
public fun <A> EagerEffect<None, A>.toOption(): Option<A> = option { invoke() }

/** Run the [Effect] by returning [Result] of [A], [orElse] run the fallback lambda and returning its result of [Result] of [A]. */
public suspend fun <E, A> Effect<E, A>.toResult(orElse: suspend (E) -> Result<A>): Result<A> =
fold({ Result.failure(it) }, { orElse(it) }, { Result.success(it) })
Expand All @@ -45,6 +53,3 @@ public inline fun <E, A> EagerEffect<E, A>.toResult(orElse: (E) -> Result<A>):
/** Run the [Effect] by returning [Result] of [A], or [Result.Failure] if raised with [Throwable]. */
public suspend fun <A> Effect<Throwable, A>.toResult(): Result<A> = result { invoke() }
public fun <A> EagerEffect<Throwable, A>.toResult(): Result<A> = result { invoke() }

public suspend fun <A> Effect<A, A>.merge(): A = fold(::identity, ::identity)
public fun <A> EagerEffect<A, A>.merge(): A = fold(::identity, ::identity)