如何在scalaz`\/表示法中累积可丢弃项

如何在scalaz`\/表示法中累积可丢弃项,scala,functional-programming,scalaz,applicative,either,Scala,Functional Programming,Scalaz,Applicative,Either,假设我有两个计算结果列表 val a: List[ Throwable \/ A] = ... val b: List[ Throwable \/ B] = ... 我有一个计算最终结果的函数,比如 def calc(a: A, b: B): Throwable \/ C = ... 我需要计算每个a和b的所有结果,如果有,还需要累积Throwable。 有没有像应用程序风格那样优雅的方式 UPDT:结果必须如下 val c: List[ Throwable \/ C] .. 我找到的最好

假设我有两个计算结果列表

val a: List[ Throwable \/ A] = ...
val b: List[ Throwable \/ B] = ...
我有一个计算最终结果的函数,比如

def calc(a: A, b: B): Throwable \/ C = ...
我需要计算每个
a
b
的所有结果,如果有,还需要累积
Throwable
。 有没有像应用程序风格那样优雅的方式

UPDT:结果必须如下

val c: List[ Throwable \/ C] ..
我找到的最好的解决办法是

def combine[A, B, C](f: (A, B) => Throwable \/ C, a: Throwable \/ A, b: Throwable \/ B): List[Throwable] \/ C = (a, b) match{
    case ( -\/(errA), \/-(_)) => -\/(List(errA))
    case (\/-(_), -\/(errB)) => -\/(List(errB))
    case (-\/(errA), -\/(errB)) => -\/(List(errA, errB))
    case (\/-(valA), \/-(valB)) => f(valA, valB).leftMap( List(_))
  }

val result = (a |@| b)(combine(calc, _, _))

但在这种情况下,我有一些额外的结果。结果列表的类型是[code>list[list[Throwable]\/C]

我不确定我是否完全理解这个问题,但我会尝试一下,希望它足够接近,以便您进行推断。假设您有一个类型为
Throwable\/a
的值列表和另一个类型为
Throwable\/B
的值列表,并且您希望将它们成对地与一个函数
(a,B)=>Throwable\/C
组合成一个累积错误列表或
C
s列表。我会这样写:

import scalaz._, Scalaz._

def process[A, B, C](
  as: List[Throwable \/ A],
  bs: List[Throwable \/ B]
)(f: (A, B) => Throwable \/ C): NonEmptyList[Throwable] \/ List[C] = ???
我们有很多方法可以实现这一点,但基本思想是,我们需要将析取临时转换为验证,以获得我们想要的错误累积(有关为什么需要这样做的一些讨论,请参见我的问题)

在这里,我们将每对值转换为验证,使用applicative
元组来组合它们,同时累积错误,转换回析取,以便我们可以绑定到
f
,返回到验证,以便我们可以使用
traverseU
应用排序,然后返回析取


(请注意,我假设列表的长度相同,或者您不介意忽略其中任何一个列表中的额外结果,但这只是为了简单起见,如果您需要其他行为,可以很容易地进行调整。)

最后,我找到了一个合适的解决方案。这个想法是使用monad变压器

接下来是魔术:

val result = (aT |@| bT)(calc( _, _ ))
// c: scalaz.EitherT[[+A]List[A],Throwable,C] = ...
在这里,我们从“a”中获得所有“good”*值,从“b”中获得所有“good”值,就像通常的应用程序风格函数调用一样。结果中没有额外的函数或额外的数据

“*”-术语“good”表示不可“丢弃”

这个想法是将函数
calc
a
中的所有“good”值与
b
中的所有“good”值组合在一起,因此结果将是
列表[Throwable\/C]
并附加
a
中的所有“bad”值和所有“bad”从
b
到最终结果列表的值。
val a: List[Throwable \/ A] = ...
val b: List[Throwable \/ B] = ...
val aT = EitherT.eitherT(a)
// aT: scalaz.EitherT[List,Throwable, A] = ...
val bT = EitherT.either(b)
// bT: scalaz.EitherT[List,Throwable, B] = ...
val result = (aT |@| bT)(calc( _, _ ))
// c: scalaz.EitherT[[+A]List[A],Throwable,C] = ...