我在下面的通用函数中遇到了该函数,它需要两个Either
类型和一个函数作为参数。如果两个参数均为Either.Right
,则对其应用函数并返回结果;如果任何参数均为Either.Left
,则其返回NonEmptyList(Either.Left)。基本上,它执行独立操作并累积错误。
fun <T, E, A, B> constructFromParts(a: Either<E, A>, b: Either<E, B>, fn: (Tuple2<A, B>) -> T): Either<Nel<E>, T> {
val va = Validated.fromEither(a).toValidatedNel()
val vb = Validated.fromEither(b).toValidatedNel()
return Validated.applicative<Nel<E>>(NonEmptyList.semigroup()).map(va, vb, fn).fix().toEither()
}
val error1:Either<String, Int> = "error 1".left()
val error2:Either<String, Int> = "error 2".left()
val valid:Either<Nel<String>, Int> = constructFromParts(
error1,
error2
){(a, b) -> a+b}
fun main() {
when(valid){
is Either.Right -> println(valid.b)
is Either.Left -> println(valid.a.all)
}
}
以上代码打印
[error 1, error 2]
在函数内部,它将Either转换为ValidatedNel类型并累积两个错误
(无效(e = NonEmptyList(all = [错误1]))无效(e = NonEmptyList(all = [错误2])))
我的问题是它如何执行此操作,或者有人可以从代码中解释以下内容。
return Validated.applicative<Nel<E>>(NonEmptyList.semigroup()).map(va, vb, fn).fix().toEither()
最佳答案
假设我有一个与Validated
类似的数据类型,称为ValRes
sealed class ValRes<out E, out A> {
data class Valid<A>(val a: A) : ValRes<Nothing, A>()
data class Invalid<E>(val e: E) : ValRes<E, Nothing>()
}
如果我有两个
ValRes
类型的值,并且想将它们组合起来以累积错误,则可以编写如下函数:fun <E, A, B> tupled(
a: ValRes<E, A>,
b: ValRes<E, B>,
combine: (E, E) -> E
): ValRes<E, Pair<A, B>> =
if (a is Valid && b is Valid) valid(Pair(a.a, b.a))
else if (a is Invalid && b is Invalid) invalid(combine(a.e, b.e))
else if (a is Invalid) invalid(a.e)
else if (b is Invalid) invalid(b.e)
else throw IllegalStateException("This is impossible")
Valid
,则构建两个值一对Invalid
实例combine
函数来构建包含两个值的Invalid
实例。 用法:
tupled(
validateEmail("stojan"), //invalid
validateName(null) //invalid
) { e1, e2 -> "$e1, $e2" }
这以通用的方式工作,而与类型E,A和B无关。但是它仅适用于两个值。我们可以为
ValRes
类型的N个值构建这样的函数。现在回到箭头:
Validated.applicative<Nel<E>>(NonEmptyList.semigroup()).map(va, vb, fn).fix().toEither()
tupled
与map
(具有硬编码成功功能)相似。这里的va
和vb
与我的示例中的a
和b
相似。这里没有返回一对值,而是有一个自定义函数(fn
),该函数在成功的情况下将两个值组合在一起。合并错误:
interface Semigroup<A> {
/**
* Combine two [A] values.
*/
fun A.combine(b: A): A
}
箭头中的
Semigroup
是一种将来自同一类型的两个值组合到一个相同类型的值中的方法。类似于我的combine
函数。 NonEmptyList.semigroup()
是Semigroup
的NonEmptyList
的实现,给定两个列表,将元素一起添加到单个NonEmptyList
中。总结一下:
Valid
->它将使用提供的函数Valid
而一个为Invalid
->则返回错误Invalid
->使用Semigroup
实例的Nel
实例合并错误在引擎盖下,它最多可缩放2个X值(我相信是22个)。