
commonMain.arrow.core.raise.Builders.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of arrow-core Show documentation
Show all versions of arrow-core Show documentation
Functional companion to Kotlin's Standard Library
@file:JvmMultifileClass
@file:JvmName("RaiseKt")
@file:OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class)
package arrow.core.raise
import arrow.atomic.Atomic
import arrow.atomic.updateAndGet
import arrow.core.Either
import arrow.core.EmptyValue
import arrow.core.Ior
import arrow.core.IorNel
import arrow.core.NonEmptyList
import arrow.core.NonEmptySet
import arrow.core.None
import arrow.core.Option
import arrow.core.Some
import arrow.core.getOrElse
import arrow.core.identity
import arrow.core.none
import arrow.core.some
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.experimental.ExperimentalTypeInference
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
@RaiseDSL
public inline fun singleton(
raise: () -> A,
@BuilderInference block: SingletonRaise.() -> A,
): A {
contract {
callsInPlace(raise, InvocationKind.AT_MOST_ONCE)
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
return recover({ block(SingletonRaise(this)) }) { raise() }
}
/**
* Runs a computation [block] using [Raise], and return its outcome as [Either].
* - [Either.Right] represents success,
* - [Either.Left] represents logical failure.
*
* This function re-throws any exceptions thrown within the [Raise] block.
*
* Read more about running a [Raise] computation in the
* [Arrow docs](https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#running-and-inspecting-results).
*/
public inline fun either(@BuilderInference block: Raise.() -> A): Either {
contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) }
return fold(block, { Either.Left(it) }, { Either.Right(it) })
}
/**
* Runs a computation [block] using [Raise], and return its outcome as nullable type,
* where `null` represents logical failure.
*
* This function re-throws any exceptions thrown within the [Raise] block.
*
* Read more about running a [Raise] computation in the
* [Arrow docs](https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#running-and-inspecting-results).
*
* @see SingletonRaise.ignoreErrors By default, `nullable` only allows raising `null`.
* Calling [ignoreErrors][SingletonRaise.ignoreErrors] inside `nullable` allows to raise any error, which will be returned to the caller as if `null` was raised.
*/
public inline fun nullable(block: SingletonRaise.() -> A): A? {
contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) }
return singleton({ null }, block)
}
/**
* Runs a computation [block] using [Raise], and return its outcome as [Result].
*
*
* Read more about running a [Raise] computation in the
* [Arrow docs](https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#running-and-inspecting-results).
*/
public inline fun result(block: ResultRaise.() -> A): Result {
contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) }
return fold({ block(ResultRaise(this)) }, Result.Companion::failure, Result.Companion::failure, Result.Companion::success)
}
/**
* Runs a computation [block] using [Raise], and return its outcome as [Option].
* - [Some] represents success,
* - [None] represents logical failure.
*
* This function re-throws any exceptions thrown within the [Raise] block.
*
* Read more about running a [Raise] computation in the
* [Arrow docs](https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#running-and-inspecting-results).
*/
public inline fun option(block: SingletonRaise.() -> A): Option {
contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) }
return singleton(::none) { block().some() }
}
/**
* Runs a computation [block] using [Raise], and return its outcome as [Ior].
* - [Ior.Right] represents success,
* - [Ior.Left] represents logical failure which made it impossible to continue,
* - [Ior.Both] represents that some logical failures were raised,
* but it was possible to continue until producing a final value.
*
* This function re-throws any exceptions thrown within the [Raise] block.
*
* In both [Ior.Left] and [Ior.Both] cases, if more than one logical failure
* has been raised, they are combined using [combineError].
*
* Read more about running a [Raise] computation in the
* [Arrow docs](https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#running-and-inspecting-results).
*/
public inline fun ior(noinline combineError: (Error, Error) -> Error, @BuilderInference block: IorRaise.() -> A): Ior {
contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) }
val state: Atomic = Atomic(EmptyValue)
return fold(
{ block(IorRaise(combineError, state, this)) },
{ e -> Ior.Left(EmptyValue.combine(state.get(), e, combineError)) },
{ a -> EmptyValue.fold(state.get(), { Ior.Right(a) }, { e: Error -> Ior.Both(e, a) }) }
)
}
/**
* Run a computation [block] using [Raise]. and return its outcome as [IorNel].
* - [Ior.Right] represents success,
* - [Ior.Left] represents logical failure which made it impossible to continue,
* - [Ior.Both] represents that some logical failures were raised,
* but it was possible to continue until producing a final value.
*
* This function re-throws any exceptions thrown within the [Raise] block.
*
* In both [Ior.Left] and [Ior.Both] cases, if more than one logical failure
* has been raised, they are combined using [combineError]. This defaults to
* combining [NonEmptyList]s by concatenating them.
*
* Read more about running a [Raise] computation in the
* [Arrow docs](https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#running-and-inspecting-results).
*/
public inline fun iorNel(noinline combineError: (NonEmptyList, NonEmptyList) -> NonEmptyList = { a, b -> a + b }, @BuilderInference block: IorRaise>.() -> A): IorNel {
contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) }
return ior(combineError, block)
}
/**
* Runs a computation [block] using [Raise], and ignore its outcome.
*
* This function re-throws any exceptions thrown within the [Raise] block.
*
* Read more about running a [Raise] computation in the
* [Arrow docs](https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#running-and-inspecting-results).
*/
public inline fun impure(block: SingletonRaise.() -> Unit) {
contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) }
return singleton({ }, block)
}
public class SingletonRaise(private val raise: Raise): Raise {
@RaiseDSL
public fun raise(): Nothing = raise.raise(Unit)
@RaiseDSL
override fun raise(r: E): Nothing = raise()
@RaiseDSL
public fun ensure(condition: Boolean) {
contract { returns() implies condition }
return if (condition) Unit else raise()
}
@RaiseDSL
public fun Option.bind(): A {
contract { returns() implies (this@bind is Some) }
return getOrElse { raise() }
}
@RaiseDSL
public fun A?.bind(): A {
contract { returns() implies (this@bind != null) }
return this ?: raise()
}
@RaiseDSL
public fun ensureNotNull(value: A?): A {
contract { returns() implies (value != null) }
return value ?: raise()
}
@RaiseDSL
@JvmName("bindAllNullable")
public fun Map.bindAll(): Map =
mapValues { (_, v) -> v.bind() }
@JvmName("bindAllOption")
public fun Map>.bindAll(): Map =
mapValues { (_, v) -> v.bind() }
@RaiseDSL
@JvmName("bindAllNullable")
public fun Iterable.bindAll(): List =
map { it.bind() }
@RaiseDSL
@JvmName("bindAllOption")
public fun Iterable
© 2015 - 2025 Weber Informatics LLC | Privacy Policy