我正在尝试在 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()) }
您最终会调用 somethingSpecific
上B
.
无论如何,抽象方法方法都是不可能的。
使用通用扩展来实现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
,因为L
和R
不受约束。
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>
}
如果您确实将它们限制为 A
和Int
,您将无法调用flatMap
在Either<Any, Int>
上.
关于kotlin - 在 Kotlin 中实现并输入 Either,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76819129/