sealed class Either<out L : Any?, out R : Any?>(protected open val l: L?, protected open val r: R?) {
class Left<out L : Any>(override val l: L) : Either<L, Nothing>(l, null) {
override fun <T1 : Any, T2 : Any> map(ifLeft: ((L) -> T1)?, ifRight: ((Nothing) -> T2)?) = Left(ifLeft!!.invoke(l))
override fun swap() = Right(l)
override fun <T> case(left: ((L) -> T)?, right: ((Nothing) -> T)?) = left!!.invoke(l)
override fun <C> case(left: C, right: C) = left
override fun toString() = "Left: $l"
override fun equals(other: Any?) = this === other || (other is Left<*> && l == other.l)
override fun hashCode() = l.hashCode()
}
class Right<out R : Any>(override val r: R) : Either<Nothing, R>(null, r) {
override fun <T1 : Any, T2 : Any> map(ifLeft: ((Nothing) -> T1)?, ifRight: ((R) -> T2)?) = Right(ifRight!!.invoke(r))
override fun swap() = Left(r)
override fun <T> case(left: ((Nothing) -> T)?, right: ((R) -> T)?) = right!!.invoke(r)
override fun <C> case(left: C, right: C) = right
override fun toString() = "Right: $r"
override fun equals(other: Any?) = this === other || (other is Right<*> && r == other.r)
override fun hashCode() = r.hashCode()
}
fun isLeft() = l !== null
fun isRight() = r !== null
fun left() = l!!
fun right() = r!!
abstract fun <C> case(left: C, right: C): C
abstract fun <T> case(left: ((L) -> T)?, right: ((R) -> T)?): T
abstract fun <T1 : Any, T2 : Any> map(ifLeft: ((L) -> T1)?, ifRight: ((R) -> T2)?): Either<T1, T2>
abstract fun swap(): Either<R, L>
}
That's much easier to read and use