Scala 中的 FP 的第 7 章討論了創建一個純函式庫來處理并發。為此,它定義了一個型別
type Par[A] = ExecutorService => Future[A]
以及fork等一組有用的功能
def fork[A] (a: => Par[A]): Par[A] =
es => es.submit(new Callable[A] {
def call = a(es).get
})
其中一個練習是關于具有以下簽名的函式序列
def sequence[A](ps: List[Par[A]]): Par[List[A]]
使用 foldRight 的解決方案很簡單。然而,作者包括了另外兩個版本作為答案,其中一個陳述如下
// This implementation forks the recursive step off to a new logical thread,
// making it effectively tail-recursive. However, we are constructing
// a right-nested parallel program, and we can get better performance by
// dividing the list in half, and running both halves in parallel.
// See `sequenceBalanced` below.
def sequenceRight[A](as: List[Par[A]]): Par[List[A]] =
as match {
case Nil => unit(Nil)
case h :: t => map2(h, fork(sequenceRight(t)))(_ :: _)
}
我不太確定“有效尾遞回”是什么意思。從 fork 的定義中可以清楚地看出它接受一個按名稱引數,因此map2(h, fork(sequenceRight(t)))(_ :: _)不會評估第二個引數(直到提供執行程式服務)。但這并沒有告訴我它是如何以及為什么“有效地尾遞回”的。
uj5u.com熱心網友回復:
讓我們來一些List(a, b, c)。傳入后sequenceRight會變成:
map2(
a,
fork(
map2(
b,
fork(
map2(
c,
fork(unit(Nil)
)(_ :: _)
)
)(_ :: _)
)
)(_ :: _)
這根本不是尾遞回,編譯器不能將其視為一個。但是,當您評估它的執行方式時:
fork會讓你傳遞給它的任何東西異步,所以它會立即回傳,map2實作不會阻塞執行,直到fork被執行以應用傳遞給的函式map2,相反,它會異步轉換計算的結果以fork添加值- 由于遞回是異步完成的,因此將內容發布到 ExecutorService 并附加操作,
Future讓您將 ExecutorService Future 視為蹦床
結果實際發生的是:
sequenceRight(List(a, b, c))呼叫`map2(a, fork(sequenceRight(List(b, c))(_ :: _)a將在完成時完成,但即使現在我們也可以將其作為價值持有fork(sequenceRight(List(b, c))已經安排好了,但我們不會等到它完成,我們已經可以傳遞它了- 我們可以創建一個
Future組合上面 2 的結果(并回傳它),而無需等待它們中的任何一個完成!
- 結果,
Future立即回傳!它仍在運行,但這一呼叫已完成! Future遞回創建的 s也是如此- 一次完成
c,計算fork(unit(Nil))rResult :: Nil - 這允許完成
bResult :: cResult :: Nil - 這最終允許計算最終結果
換句話說,尾遞回是指將遞回呼叫重寫為while回圈以避免堆疊溢位。但是只有在同步進行遞回呼叫時,堆疊溢位才是一個問題。如果你回傳異步的東西,那么回溯會被推送到 ExecutionServices 和 Futures 的觀察者,所以它們被隱藏在一個堆中。從這個角度來看,它們解決了與尾遞回呼叫相同的堆疊溢位問題,因此“在精神上”它們可以被認為有些相似。
uj5u.com熱心網友回復:
這當然不是尾遞回,我認為他們知道這一點——這就是他們“有效地”添加的原因:)。
他們的意思是,這個實作不會在堆疊上為遞回呼叫創建額外的幀,這是真的,因為這些呼叫是異步發生的,正如您所指出的。
現在,這種情況是否甚至值得稱為“遞回”是一個很好的問題。我認為對此沒有一個公認的答案。我個人傾向于“是”,因為將遞回定義為“參考自身”肯定包括這種情況,而且我真的不知道如何定義它以便排除異步呼叫,但尾遞回不是。
順便說一句,我不是 Javascript 方面的專家,但我聽說“異步遞回”這個詞在那里使用得相當廣泛。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/415349.html
標籤:
上一篇:何時使用隱式引數
