kotlin - 如何使用带左方差注释的 flatMap vavr Either

标签 kotlin functional-programming vavr

我的代码

open class Fail(override val message: String, override val cause: Throwable?) : RuntimeException(message, cause)

data class ValidationFail(override val message: String, override val cause: Throwable?) : Fail(message, cause)

以后会在那里定义更多的失败

我有两个功能

fun fun1(): Either<out Fail, A>
fun fun2(a: A): Either<out Fail, B>

当我尝试像这样调用它们时 fun1().flatMap{fun2(it)} 我得到了

Type mismatch: inferred type is (A!) -> Either<out Fail, B> but ((A!) -> Nothing)! was expected. Projected type Either<out Fail, A> restricts use of public final fun <U : Any!> flatMap(p0: ((R!) -> Either<L!, out U!>!)!): Either<L!, U!>! defined in io.vavr.control.Either

来自 vavr 的代码:

default <U> Either<L, U> flatMap(Function<? super R, ? extends Either<L, ? extends U>> mapper) {
    Objects.requireNonNull(mapper, "mapper is null");
    if (isRight()) {
        return (Either<L, U>) mapper.apply(get());
    } else {
        return (Either<L, U>) this;
    }
}

我猜 o 有这个错误是因为 flatMap 定义中有 L 而不是 ?扩展 L

有什么解决方法吗?

最佳答案

在您的特定情况下,您可以通过从 fun1fun2 返回类型中删除 out 差异来使其编译。 You shouldn't use wildcard types as return types anyway .

但是,如果您以这种方式定义了 fun1fun2,那将无济于事:

fun fun1(): Either<ConcreteFail1, A>
fun fun2(a: A): Either<ConcreteFail2, B>

替换 LflatMap 签名中的 extends L 也无济于事,因为 ConcreteFail2 不是 ConcreteFail1 的子类型。问题是 Either 应该是协变的,但在 Java 中没有声明位点差异这样的东西。虽然有一个使用 Either#narrow 的解决方法方法:

Either.narrow<Fail, A>(fun1()).flatMap { Either.narrow(fun2(it)) }

当然,它看起来很奇怪,必须提取到一个单独的扩展函数中:

inline fun <L, R, R2> Either<out L, out R>.narrowedFlatMap(
    crossinline mapper: (R) -> Either<out L, out R2>
): Either<L, R2> = narrow.flatMap { mapper(it).narrow }

narrow 是:

val <L, R> Either<out L, out R>.narrow: Either<L, R> get() = Either.narrow(this)

我认为 Vavr 没有提供它自己的 narrowedFlatMap 因为这个方法需要使用通配符接收器类型,所以它不能是一个成员方法,必须是一个静态的,它打破了操作流水线的所有可读性:

narrowedFlatMap(narrowedFlatMap(narrowedFlatMap(fun1()) { fun2(it) }) { fun3(it) }) { fun4(it) }

但由于我们使用 Kotlin,我们也可以管道化静态(扩展)函数:

fun1().narrowedFlatMap { fun2(it) }.narrowedFlatMap { fun3(it) }.narrowedFlatMap { fun4(it) }

关于kotlin - 如何使用带左方差注释的 flatMap vavr Either,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58841465/

相关文章:

java - Kotlin 和数据绑定(bind) Int 值 null 检查问题

android - 适用于 Android 的类似 iOS 的抽屉导航?

scala - 为什么 Finatra 使用 flatMap 而不仅仅是 map ?

java - 从可选值的供应商序列中提取第一个定义值(如果有)

android - 在 JNI 中使用错误代码将 jbytearray 转换为 char*

kotlin - 重组后如何保持对元素的关注?

collections - 从 Vec<Vec<char>> 创建一个 Vec<BTreeSet<char>>

testing - 使用 ExUnit 进行测试时如何伪造 IO 输入?

java - 如何用vavr修复函数的第二个参数?

java-8 - Vavr性能测试