既然你已經標記此哈斯克爾,我會在這方面的回答:在Haskell,做CPS變換相當於在Cont
單子,其轉換價值x
成高階函數工作是採用一個參數並將其應用於x
。
所以,首先,這裏是1 + 2規則哈斯克爾:(1 + 2)
這裏,它是在延續單子:
contAdd x y = do x' <- x
y' <- y
return $ x' + y'
...不是非常翔實。爲了看看發生了什麼,讓我們拆開monad。首先,除去do
符號:
contAdd x y = x >>= (\x' -> y >>= (\y' -> return $ x' + y'))
的return
函數升降機一個值到單子,並且在這種情況下被實施爲\x k -> k x
,或使用中綴運算符截面\x -> ($ x)
。
contAdd x y = x >>= (\x' -> y >>= (\y' -> ($ x' + y')))
的(>>=)
操作(讀「綁定」)鏈一起計算在單子,並且在這種情況下被實現爲\m f k -> m (\x -> f x k)
。更改綁定功能,以前綴的形式,並在拉姆達取代,再加上一些重命名爲清楚:
contAdd x y = (\m1 f1 k1 -> m1 (\a1 -> f1 a1 k1)) x (\x' -> (\m2 f2 k2 -> m2 (\a2 -> f2 a2 k2)) y (\y' -> ($ x' + y')))
減少一些功能的應用:
contAdd x y = (\k1 -> x (\a1 -> (\x' -> (\k2 -> y (\a2 -> (\y' -> ($ x' + y')) a2 k2))) a1 k1))
contAdd x y = (\k1 -> x (\a1 -> y (\a2 -> ($ a1 + a2) k1)))
,有點最後的清理和重命名:
contAdd x y = \k -> x (\x' -> y (\y' -> k $ x' + y'))
換句話說:函數的參數已經從數字變成了函數,該函數需要一個數字並返回整個表達式的最終結果,像你所期望的那樣。
編輯:一位評論者指出,contAdd
本身仍然採用咖喱風格的兩個參數。這是明智的,因爲它不直接使用延續,但不是必需的。如果不這樣做,你需要先打散參數的函數關係:
contAdd x = x >>= (\x' -> return (\y -> y >>= (\y' -> return $ x' + y')))
,然後用它是這樣的:
foo = do f <- contAdd (return 1)
r <- f (return 2)
return r
注意,這是從早期版本確實沒有不同;它只是將每個部分應用程序的結果打包爲一個延續,而不僅僅是最終結果。由於函數是第一類值,因此保持數字的CPS表達式與保持函數的CPS表達式之間沒有顯着差異。
請記住,我在這裏以非常冗長的方式寫出所有步驟,以明確所有步驟,其中某些東西是連續傳遞樣式。
附錄:您可能會注意到,最終表達式看起來與monadic表達式的脫糖版非常相似。這並不是巧合,因爲單調錶達式的內在嵌套性使得他們根據先前的值改變計算結構與延續傳遞風格密切相關;在這兩種情況下,你都有某種意義上的因果關係的概念。
也許我是唯一一個不知道CPS在這方面意味着什麼的人。 :-) 或者可能不是。如果不是:http://en.wikipedia.org/wiki/Continuation-passing_style – 2010-12-22 16:56:12
請注意,CPS有兩種形式:它是範例(例如Cont)或實現細節(例如Codensity)。前者當然會將每個函數轉換爲函數函數,即它增加了另一個參數。在後者中,它就是如何在引擎蓋下實現的。一些語言在所有地方使用CPS,同時提供非CPS接口,Scheme是典型示例。但是,大多數Scheme實現繼續前進,並將該實現細節公開爲一種名爲call/cc的語言功能。 – ertes 2013-06-02 07:42:18