這是延續傳球風格。
JavaScript是Lisp的,但穿的語法C.
,因爲JavaScript是其核心函數式語言的衣服,很瘋狂的招數是可能的,就像路過延續風格。但這些技巧令人頭痛。
總的來說,延續是下一步做什麼的概念 - 作爲你可以調用的東西,就像一個函數一樣。我有時也會將延續視爲已保存的調用幀堆棧:您可以將一堆函數調用保存爲執行狀態,並稍後返回或僅「調用」此狀態。
有人表示,通過將代碼轉換爲連續傳遞樣式,您可以獲得延續的力量。哇!這真的很令人印象深刻:
只是一個源代碼轉換和whooosh你有延續的力量。
現在,Javascript的問題是它的C語法。使用C語法進行源代碼轉換是很困難的。使用Lisp語法會更容易,但仍然乏味且容易出錯。
我們很幸運,一些非常聰明的人爲我們做了艱苦的工作。這項艱鉅的工作需要使用JavaScript解析器,因爲這種轉換真的意味着什麼?在一個總結中,它意味着重新排序操作的順序,以便首先真正完成的任務先行。
f(g(a + x))
添加a + x
首先做了,那麼函數調用g()
然後f()
。有三個子表達式。在CPS轉換中,子表達式的結果被傳遞給繼續。這涉及到創建許多內部幫助函數作爲臨時延續。這會變得複雜而乏味,我們將在下面看到。
在http://en.wikipedia.org/wiki/Continuation-passing_style示例功能
(define (pyth x y)
(sqrt (+ (* x x) (* y y))))
轉換爲
(define (pyth& x y k)
(*& x x (lambda (x2)
(*& y y (lambda (y2)
(+& x2 y2 (lambda (x2py2)
(sqrt& x2py2 k))))))))
這對應於Javacript
function pyth(x, y) {
return Math.sqrt(x * x + y * y);
}
但*,+和Math.sqrt()不是函數CPS會有意義。
但讓我們假設*,+和Math.sqrt()是Web服務的例子。這很重要,因爲Javascript Web服務調用是異步。每個使用異步調用的人都知道如何將它們的結果組合起來。使用預處理庫或生成器可以更輕鬆地處理異步結果。
讓我們寫在一個不同的方式例如:
function pyth(x, y) {
return sqrt(add(mul(x, x), mul(y, y)));
}
那麼CPS變換看起來是這樣的:
function pyth_cps(x, y, k) {
mul_cps(x, x, function(x2) {
mul_cps(y, y, function(y2) {
add_cps(x2, y2, function(x2py2) {
sqrt_cps(x2py2, k);
})
})
});
}
我們看到產生的代碼被撕裂由內向外,積極提出不可讀。每個功能都被轉換。他們都得到了一個神奇的參數k。這是延續。在JavaScript中,它是一個獲取操作結果的函數。在調用堆棧k內部的某處調用。在我們的例子中,在這裏沒有顯示sqrt()的CPS轉換。
另請注意,CPS轉換函數不會返回。他們只是將計算結果稱爲延續。這可能導致堆棧耗盡。所有Javascript CPS變形金剛需要處理這個。在Scheme中,這不是必需的,因爲所有的調用都是尾調用。尾部調用不需要額外的調用框架。在JavaScript中需要使用蹦牀或類似技術。不是直接調用continuation,而是調用helper並將結果和延續傳遞給它。助手以無限循環運行,始終調用並返回並避免堆棧耗盡。
那麼,爲什麼這個CPS給我們延續的力量呢?那是因爲接下來就是接下來要做的事。如果我們總是將這個概念作爲一個附加參數k來傳遞,並且總是將當前表達式的結果傳遞給它,那麼我們已經在代碼中實現了這個概念。但是,正如我們所看到的,這個「總是隨身攜帶」是很乏味的。
即使我們讓源代碼預處理器做了艱苦的工作,這也是一個陡峭的代價。我們爲什麼要使用延續?抽象控制流是可能的。 Seaside是一個Web應用程序框架,它使用continuation來抽象瀏覽器的無狀態請求流。用戶交互可以簡潔地建模 - 人們不再在請求中思考,而是在交互流中進行思考。這只是延續力量的衆多例子之一。這種力量對許多人來說似乎也很古怪,有點可怕。
我很瞭解CPS,但是轉換通用命令代碼a-la-javascript並不那麼簡單。你如何從順序代碼自動轉換爲CPS? – 2012-02-22 11:42:20
首先解析源代碼,然後重新排列表達式,以便評估第一個子表達式並將表達式的結果傳遞給繼續。 I. e。按照此處所述執行:http://en.wikipedia.org/wiki/Continuation-passing_style,但使用Javascript。 – nalply 2012-02-22 12:45:04