def map2[A,B,C] (a: Par[A], b: Par[B]) (f: (A,B) => C) : Par[C] =
(es: ExecutorService) => {
val af = a (es)
val bf = b (es)
UnitFuture (f(af.get, bf.get))
}
def map3[A,B,C,D] (pa :Par[A], pb: Par[B], pc: Par[C]) (f: (A,B,C) => D) :Par[D] =
map2(map2(pa,pb)((a,b)=>(c:C)=>f(a,b,c)),pc)(_(_))
我有map2,需要根据map2生成map3。我在GitHub中找到了解决方案,但很难理解。任何人都可以看到它并解释map3以及它的作用(())?
答案 0 :(得分:3)
在纯粹的抽象层面上,map2
意味着您可以并行运行两个任务,这本身就是一项新任务。为map3
提供的实现是:并行运行(包括并行运行两个第一个任务的任务)和(第三个任务)。
现在回到代码:首先,让我们给所有创建的对象命名(为了清晰起见,我还扩展了_
符号):
def map3[A,B,C,D] (pa :Par[A], pb: Par[B], pc: Par[C]) (f: (A,B,C) => D) :Par[D] = {
def partialCurry(a: A, b: B)(c: C): D = f(a, b, c)
val pc2d: Par[C => D] = map2(pa, pb)((a, b) => partialCurry(a, b))
def applyFunc(func: C => D, c: C): D = func(c)
map2(pc2d, pc)((c2d, c) => applyFunc(c2d, c)
}
现在请记住map2
需要两个Par[_]
,以及一个合并最终值的函数,以获得结果的Par[_]
。
第一次使用map2
(内部版本)时,您将前两个任务并行化,并将它们组合成一个函数。实际上,使用f
,如果您具有类型A
的值和类型B
的值,则只需要类型C
的值来构建类型{ {1}},这恰恰意味着D
是partialCurry(a, b)
类型的函数(C => D
本身属于partialCurry
类型)。
现在您再次有两个(A, B) => C => D
类型的值,因此您可以再次Par[_]
,并且只有一种自然方式可以将它们组合起来以获得最终值。
答案 1 :(得分:0)
上一个答案是正确的,但我发现这样子更容易:
def map3[A, B, C, D](a: Par[A], b: Par[B], c: Par[C])(f: (A, B, C) => D): Par[D] = {
val f1 = (a: A, b: B) => (c: C) => f(a, b, c)
val f2: Par[C => D] = map2(a, b)(f1)
map2(f2, c)((f3: C => D, c: C) => f3(c))
}
创建一个函数f1
,它是f
的一个版本,其中部分应用了前2个自变量,然后我们可以map2
来使用a
和b
在C => D
上下文(Par
)中为我们提供类型为f1
的函数。
最后,我们可以使用f2
和c
作为map2
的参数,然后将f3
(C => D
)应用于c
给我们一个D
中的Par
。
希望这对某人有帮助!