Skip to content

Instantly share code, notes, and snippets.

@ywett02
Created February 24, 2023 16:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ywett02/47a183100b1e9228111c9b0bafa6c658 to your computer and use it in GitHub Desktop.
Save ywett02/47a183100b1e9228111c9b0bafa6c658 to your computer and use it in GitHub Desktop.
import kotlin.contracts.contract
sealed class Either<out E, out V> {
data class Error<out E>(val error: E) : Either<E, Nothing>()
data class Value<out V>(val value: V) : Either<Nothing, V>()
}
typealias Left<T> = Either.Error<T>
typealias Right<T> = Either.Value<T>
@Suppress("FunctionName", "NOTHING_TO_INLINE")
inline fun <V> Value(value: V): Either<Nothing, V> = Either.Value(value)
@Suppress("FunctionName", "NOTHING_TO_INLINE")
inline fun <E> Error(value: E) = Either.Error(value)
suspend fun <V> either(action: suspend () -> V): Either<Throwable, V> =
try {
Value(action())
} catch (t: Exception) {
Error(t)
}
fun <E, V> Either<E, V>.value(): V? = when (this) {
is Either.Error -> null
is Either.Value -> value
}
fun <E, V> Either<E, V>.isError(): Boolean {
contract {
returns(true) implies (this@isError is Either.Error)
}
return this is Either.Error
}
fun <E, V> Either<E, V>.isValue(): Boolean {
contract {
returns(true) implies (this@isValue is Either.Value)
}
return this is Either.Value
}
inline fun <E, V, V2> Either<E, V>.map(func: (V) -> V2): Either<E, V2> = when (this) {
is Either.Error -> this
is Either.Value -> Either.Value(func(value))
}
inline fun <E, V, E2> Either<E, V>.mapError(func: (E) -> E2): Either<E2, V> = when (this) {
is Either.Error -> Either.Error(func(error))
is Either.Value -> this
}
inline fun <E, V, V2> Either<E, List<V>>.mapIterable(func: (V) -> V2): Either<E, List<V2>> = when (this) {
is Either.Error -> this
is Either.Value -> Either.Value(value.map(func))
}
inline fun <E, V, V2> Either<E, V>.flatMap(func: (V) -> Either<E, V2>): Either<E, V2> =
when (this) {
is Either.Error -> this
is Either.Value -> func(value)
}
@JvmName("zipExt")
inline fun <E, V, V2, R> Either<E, V>.zip(second: Either<E, V2>, zipFce: (V, V2) -> R): Either<E, R> =
zip(this, second, zipFce)
inline fun <E, V, V2, R> zip(first: Either<E, V>, second: Either<E, V2>, zipFce: (V, V2) -> R): Either<E, R> =
when (first) {
is Either.Error -> first
is Either.Value -> {
when (second) {
is Either.Error -> second
is Either.Value -> Value(zipFce(first.value, second.value))
}
}
}
fun <E, V> Either<E, List<V>>.merge(second: Either<E, List<V>>): Either<E, List<V>> =
when (val first = this) {
is Either.Error -> first
is Either.Value -> {
when (second) {
is Either.Error -> second
is Either.Value -> Either.Value(first.value.plus(second.value))
}
}
}
inline fun <E, V, E2> Either<E, V>.flatMapError(func: (E) -> Either<E2, V>): Either<E2, V> =
when (this) {
is Either.Error -> func(error)
is Either.Value -> this
}
inline fun <E, V, A> Either<E, V>.fold(e: (E) -> A, v: (V) -> A): A = when (this) {
is Either.Error -> e(this.error)
is Either.Value -> v(this.value)
}
inline fun <E, V> Either<E, V>.onNext(func: (V) -> Unit): Either<E, V> = when (this) {
is Either.Error -> this
is Either.Value -> {
func(value)
this
}
}
inline fun <E, V> Either<E, V>.onError(func: (E) -> Unit): Either<E, V> = when (this) {
is Either.Error -> {
func(error)
this
}
is Either.Value -> this
}
inline fun <E, V, K> Either<E, List<V>>.groupBy(func: (V) -> K): Either<E, Map<K, List<V>>> = when (this) {
is Either.Error -> this
is Either.Value -> Either.Value(value.groupBy(func))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment