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

dev.mythicdrops.Either.kt Maven / Gradle / Ivy

There is a newer version: 9.0.4
Show newest version
package dev.mythicdrops

internal sealed class Either {
    data class Left(val left: E) : Either()
    data class Right(val right: A) : Either()

    fun  fold(ifLeft: (E) -> R, ifRight: (A) -> R): R =
        when (this) {
            is Left -> ifLeft(left)
            is Right -> ifRight(right)
        }

    fun  foldLeft(init: R, f: (E) -> R): R =
        fold(f) { init }

    fun  foldRight(init: R, f: (A) -> R): R =
        fold({ init }, f)

    fun  bimap(f: (E) -> F, g: (A) -> B): Either =
        fold({ left(f(it)) }, { right(g(it)) })

    fun  map(f: (A) -> B): Either =
        bimap({ it }, f)

    fun  mapLeft(f: (E) -> F): Either =
        bimap(f) { it }

    fun swap(): Either =
        fold(::right, ::left)

    companion object {
        fun  left(e: E): Either = Left(e)
        fun  right(a: A): Either = Right(a)

        fun  pure(a: A): Either = right(a)

        fun  map2(e1: Either, e2: Either, f: (A, B) -> C): Either =
            e1.fold(::left) { a -> e2.fold(::left) { b -> right(f(a, b)) } }

        fun  product(e1: Either, e2: Either): Either> =
            map2(e1, e2, ::Pair)

        fun  ap(ef: Either B>, ea: Either): Either =
            map2(ef, ea) { f, a -> f(a) }

        fun  flatMap(e: Either, f: (A) -> Either): Either =
            e.fold(::left, f)

        fun  flatMapLeft(e: Either, f: (E) -> Either): Either =
            e.fold(f, ::right)

        fun  join(e: Either>): Either =
            flatMap(e) { it }
    }
}

// These exist as extension methods because Kotlin doesn't have lower bounds checking

internal fun  Either.map2(other: Either, f: (A, B) -> C): Either =
    Either.map2(this, other, f)

internal fun  Either.product(other: Either): Either> =
    Either.product(this, other)

internal fun  Either.times(other: Either): Either> =
    Either.product(this, other)

internal fun  Either B>.ap(e: Either): Either =
    Either.ap(this, e)

internal fun  Either.flatMap(f: (A) -> Either): Either =
    Either.flatMap(this, f)

internal fun  Either.flatMapLeft(f: (E) -> Either): Either =
    Either.flatMapLeft(this, f)

internal fun  Either>.join(): Either =
    Either.join(this)

internal fun  Either.orElse(f: (E) -> A): A =
    fold(f) { it }

// Traversable for Either
// Note: The definition is duplicated because Kotlin can't type check `sequence = traverse(id)`
// Note: The definition of traverse is intentionally not `map(f).sequence()` to avoid an extra traversal

internal fun  Collection.traverse(f: (A) -> Either): Either> =
    fold(Either.pure(listOf())) { eacc, ee -> eacc.map2(f(ee)) { acc, e -> acc + e } }

internal fun  Collection>.sequence(): Either> =
    fold(Either.pure(listOf())) { eacc, ee -> eacc.map2(ee) { acc, e -> acc + e } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy