
arrow.data.EitherT.kt Maven / Gradle / Ivy
package arrow.data
import arrow.*
import arrow.core.Either
import arrow.core.Left
import arrow.core.Right
import arrow.core.flatMap
import arrow.typeclasses.Applicative
import arrow.typeclasses.Functor
import arrow.typeclasses.Monad
import arrow.typeclasses.monad
/**
* [EitherT]`` is a light wrapper on an `F<`[Either]`>` with some
* convenient methods for working with this nested structure.
*
* It may also be said that [EitherT] is a monad transformer for [Either].
*/
@higherkind data class EitherT(val value: HK>) : EitherTKind, EitherTKindedJ {
companion object {
inline operator fun invoke(value: HK>): EitherT = EitherT(value)
fun pure(b: B, MF: Applicative): EitherT = right(b, MF)
fun tailRecM(a: A, f: (A) -> EitherTKind>, MF: Monad): EitherT =
EitherT(MF.tailRecM(a, {
MF.map(f(it).ev().value) { recursionControl ->
when (recursionControl) {
is Either.Left> -> Right(Left(recursionControl.a))
is Either.Right> -> {
val b: Either = recursionControl.b
when (b) {
is Either.Left -> Left(b.a)
is Either.Right -> Right(Right(b.b))
}
}
}
}
}))
fun right(b: B, MF: Applicative): EitherT = EitherT(MF.pure(Right(b)))
fun left(a: A, MF: Applicative): EitherT = EitherT(MF.pure(Left(a)))
inline fun fromEither(value: Either, MF: Applicative = monad()): EitherT =
EitherT(MF.pure(value))
}
inline fun fold(crossinline l: (A) -> C, crossinline r: (B) -> C, FF: Functor): HK = FF.map(value, { either -> either.fold(l, r) })
inline fun flatMap(crossinline f: (B) -> EitherT, MF: Monad): EitherT = flatMapF({ it -> f(it).value }, MF)
inline fun flatMapF(crossinline f: (B) -> HK>, MF: Monad): EitherT =
EitherT(MF.flatMap(value, { either -> either.fold({ MF.pure(Left(it)) }, { f(it) }) }))
inline fun cata(crossinline l: (A) -> C, crossinline r: (B) -> C, FF: Functor): HK = fold(l, r, FF)
fun liftF(fa: HK, FF: Functor): EitherT = EitherT(FF.map(fa, { Right(it) }))
inline fun semiflatMap(crossinline f: (B) -> HK, MF: Monad): EitherT = flatMap({ liftF(f(it), MF) }, MF)
fun map(f: (B) -> C, FF: Functor): EitherT = EitherT(FF.map(value, { it.map(f) }))
inline fun mapLeft(crossinline f: (A) -> C, FF: Functor): EitherT = EitherT(FF.map(value, { it.mapLeft(f) }))
inline fun exists(crossinline p: (B) -> Boolean, FF: Functor): HK = FF.map(value, { it.exists(p) })
inline fun transform(crossinline f: (Either) -> Either, FF: Functor): EitherT = EitherT(FF.map(value, { f(it) }))
fun subflatMap(f: (B) -> Either, FF: Functor): EitherT = transform({ it.flatMap(f) }, FF)
fun toOptionT(FF: Functor): OptionT = OptionT(FF.map(value, { it.toOption() }))
fun combineK(y: EitherTKind, MF: Monad): EitherT =
EitherT(MF.flatMap(this.ev().value) {
when (it) {
is Either.Left -> y.ev().value
is Either.Right -> MF.pure(it)
}
})
fun ap(ff: EitherTKind C>, MF: Monad): EitherT = ff.ev().flatMap ({ f -> map(f, MF) }, MF)
}
fun EitherTKind.value(): HK> = this.ev().value
© 2015 - 2025 Weber Informatics LLC | Privacy Policy