All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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