kotlin - 在 Kotlin 中实现并输入 Either

标签 kotlin functional-programming

我正在尝试在 Kotlin 中实现右偏的 Either 类型,但在平面映射声明中遇到协方差问题(不在实现中):

类型参数 L 被声明为“out”,但出现在类型中的“in”位置

sealed class Either<out L, out R> {
    abstract fun isLeft(): Boolean
    abstract fun isRight(): Boolean

    abstract fun <R2> flatMap(f: (R) -> Either<L, R2>): Either<L, R2>

    fun <R2> map(f: (R) -> R2): Either<L, R2> = flatMap { Right(f(it)) }
}

data class Left<L>(val l: L): Either<L, Nothing>() {
    override fun isLeft(): Boolean = true
    override fun isRight(): Boolean = false

    override fun <R2> flatMap(f: (Nothing) -> Either<L, R2>): Either<L, R2> = this
}

data class Right<R>(val r: R): Either<Nothing, R>() {
    override fun isLeft(): Boolean = false
    override fun isRight(): Boolean = true

    override fun <R2> flatMap(f: (R) -> Either<Nothing, R2>): Either<Nothing, R2> = f(r)
}

可以通过打字来解决吗?我不想陷入带有 when 子句的外部函数

最佳答案

问题是 Kotlin 不知道你将如何实现抽象 flatMap方法。它不会去每个现有的实现来检查它们是否是类型安全的,这本身就可能非常困难。

例如,您可以实现 Either像这样,作为附加实现。

class A {
    fun somethingSpecific() {}
}
class B

class SomethingElse: Either<A, Int>() {
    override fun isLeft() = true

    override fun isRight() = true

    override fun <R2> flatMap(f: (Int) -> Either<A, R2>): Either<A, R2> {
        val x = f(1)
        when (x) {
            is Left -> x.l.somethingSpecific()
            else -> {}
        }
        return Left(A())
    }

}

你做到了:

val x: Either<Any, Int> = SomethingElse()
val y = x.flatMap { Left(B()) }

您最终会调用 somethingSpecificB .

无论如何,抽象方法方法都是不可能的。

使用通用扩展来实现flatMap相反:

fun <L, R, R2> Either<L, R>.flatMap(f: (R) -> Either<L, R2>): Either<L, R2> =
    when (this) {
        is Left -> this
        is Right -> f(this.r)
    }

请注意,与 SomethingElse 相同的技巧不能在这里完成。您无法将第三条臂添加到 when实现 SomethingElse.flatMap ,因为LR不受约束。

is SomethingElse -> {
    val x = f(1) // oops, f doesn't take an Int
    when (x) {
        is Left -> x.l.somethingSpecific() // oops, x.l is not A
        else -> {}
    }
    Left(A()) // oops, this should return Either<L, R2>, not Either<A, Nothing>
}

如果您确实将它们限制为 AInt ,您将无法调用flatMapEither<Any, Int>上.

关于kotlin - 在 Kotlin 中实现并输入 Either,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76819129/

相关文章:

Scala - 以函数方式修改字符串

haskell - 处理 SomeException 被忽略

c++ - std::ptr_fun 模板化类和结构的参数困难

javascript - __ 应该只适用于柯里化(Currying)函数吗?为什么它在这里工作?

android - 从 Android 设备卸载应用程序时如何使用 Firebase 以编程方式检测?

android - 挂起函数会挂起协程吗?

android - 如何在Kotlin中将res中的ImageView转换为Base64字符串

android - 我的 RecyclerView 没有得到适当的通知

android - SonarQube 报告中未显示测试覆盖率

scala - 在 Scala 中进行柯里化(Currying) : multiple parameter lists vs returning a function