2010-05-13 73 views
21

Continuation維基百科的文章說:
「在支持關閉任何語言,可以寫在延續傳遞風格的程序和手動執行呼叫/立方厘米。」

要麼這是真的,我需要知道如何去做,否則它是不正確的,該聲明需要糾正。

如果這是真的,請告訴我如何在Lua中實現call/cc,因爲我看不到如何。

我想我可以手動實現call/cc,如果Lua具有corruptine.clone函數,如here所解釋的那樣。

如果閉包不足以實現call/cc,那麼還需要什麼?呼叫/ cc在Lua - 可能嗎?

以下文本是可選閱讀。
P.S .: Lua對其協程表進行了一次性延續。一個coroutine.clone函數可以讓我克隆它多次調用它,從而有效地使call/cc成爲可能(除非我誤解了call/cc)。然而,克隆功能在Lua中不存在。 Lua IRC頻道上的某個人建議我使用Pluto庫(它實現序列化)來封送協同程序,複製它,然後解組並再次使用它。雖然這可能會起作用,但我對call/cc的理論實現以及查找語言爲實現其手動實現所需的實際最小特徵集合更感興趣。

編輯1:好的人,幫我在這裏,這花了我很長一段時間,因爲我不知道任何計劃,但我想出了什麼,應該幫助我們。請看下面的代碼。第一個是Scheme中的程序,第二個是Lua中的程序。
希望這會幫助我們。我相信我們非常接近

P.S .:這些示例取自the Wikipedia article on CallCC上的第一個示例。 方案版本

(define call/cc call-with-current-continuation) 

; callcc CPS-transformed (thanks to the people from the #scheme channel at freenode.net) 
(define cpscallcc 
    (lambda (consumer k) 
    (let ((cc (lambda (result) (k result)))) 
     (consumer cc k)))) 

; this is the continuation we will use to display the "returned" values 
(define main-continuation 
    (lambda (result) 
    (display "--> ") 
    (display result) 
    (newline))) 

; define f function non-CPS 
(define (f return) 
    (return 2) 
    3) 

; these are my past attempts at defining a CPS f function 
;(define (cps-f return k) 
; (k (return 2)) 3) 
;(define (cps-f return k) 
; (k (lambda() 
;  (return 2) 
;  3))) 

; this is what I came up with - I'm not sure if this is correctly CPS-transformed but I  believe so 
(define (cps-f return k) 
    (return 2) 
    (k 3)) 

; call the non-CPS f function 
(display (f (lambda (x) x))) ; displays 3 
(newline) 

; call the non-CPS f function with call/cc (I don't understand what this does) 
(display (call/cc f)) ; displays 2 
(newline) 

; now call the CPS version of the f function 
(cps-f (lambda (x) x) main-continuation) ; displays --> 3 

; now call the CPS version of the f function with the CPS version of call/cc 
(cpscallcc cps-f main-continuation) ; displays --> 2 but then it also displays --> 3 afterwards -> I'm not sure why it displays the 3 afterwards, as it should only display the 2 just like the non-CPS versions above 



Lua版本

-- callcc CPS-version 
cpscallcc = function(consumer, k) 
    local cc = function(result) 
     return k(result) -- ?or k(result) 
    end 
    return consumer(cc, k) -- ?or return consumer(cc,k) 
end 

-- define f function non-CPS 
f = function(ret) 
    ret(2) 
    return 3 
end 

-- define f function CPS-version (again, not sure this is correct) 
cps_f = function(ret, k) 
    ret(2) 
    k(3) 
end 

-- call the non-CPS f function 
print(f(function(x) return x end)) 

-- we cant call the non-CPS f function with callcc because 
-- Lua doesnt have callcc, but the line below displays the correct expected output (maybe by accident) 
--cpscallcc(f, print) 

-- now call the CPS version of the f function 
cps_f(function(x) return x end, print) -- displays 3 

; now call the CPS version of the f function with the CPS version of call/cc 
cpscallcc(cps_f, print) -- displays 2 and then 3 just like the Scheme version!! 
-- so apparently the translation from Scheme to Lua is correct... 



我使用DrScheme和Lua的Windows - 對於任何人,願意幫助了出這是兩個方便下載和安裝剛剛工作的工具。

回答

18

有兩個前提條件手動執行每維基百科報價呼叫/ CC:

  1. 語言必須支持關閉
  2. 必須在延續傳遞風格編寫程序(CPS)

我懷疑你不會喜歡#2。

要延續傳遞風格編寫程序:

  1. 每個函數必須採取一個延續參數
  2. 功能必須通過調用其延續

因此,使用k作爲名稱返回繼續的論點,功能看起來像:

function multiplyadd(k, x, y, z) return k(x * y + z) end 

頂層可以使用print作爲其延續,在最高水平,從而調用multiplyadd看起來像:

multiplyadd(print, 2, 4, 1) 

隨着該腳手架我們可以定義來電/ CC作爲

function callcc(k,f) return f(k,k) end 

注意上面multiplyadd實際上作弊,因爲*+不在CPS中。以CPS形式添加所有操作符非常繁瑣,將所有Lua庫函數替換爲CPS等價物,並將所有代碼翻譯/生成到CPS;見details here

+0

哇,你讓我真的接近理解這一點。你可以擴展callcc函數的定義嗎?特別是通過解釋允許它記住保存/記住所有狀態的部分,如Scheme的call/cc所做的。 – PeterM 2010-05-13 16:37:03

+0

我想我會遇到麻煩,如何使用這個callcc函數 - 在Scheme中你必須設置一個呼叫/ cc跳轉到的地方,但是在CPS中你不會......這讓我想起了我。 – PeterM 2010-05-13 16:43:45

+0

因爲k是callcc將返回的閉包,所以將它傳遞給它的參數f完成了call/cc的工作[我剛剛編輯了上面的定義,因爲我忘記了正確地返回]。當程序處於CPS時,這是微不足道的,因爲延續總是可用的;在Scheme中,隱藏的和call/cc的工作比較困難(在語言層面上,編譯器的實現可能很微不足道),因爲它必須「延續」這個延續。 – 2010-05-13 17:25:45

17

我想你忘了關於編寫程序的部分,繼續傳遞 的風格。一旦你這樣做,調用/ cc是微不足道的(以Lua或任何其他語言), 作爲延續將是所有功能的明確參數(請致電/ cc 包括)。

PS:除了關閉之外,還需要適當的尾部呼叫才能繼續編程 傳球風格。

+1

首先,能夠回覆我的問題非常榮幸。我完全愛上你的語言,因爲許多原因(小核心,C語言集成,非常一致的語法,真正的關閉,頭等功能等)。 現在回答:PS說明了很多。如果我要求Lua中的call/cc的示例實現是Lua允許封閉和尾部呼叫優化,那將是不禮貌的嗎? :) – PeterM 2010-05-13 16:25:19

+0

我同意下面的諾曼拉姆齊的回覆。我想一個更好的問題是,是否有計劃實施一流的延續,並因此在Lua實現callcc? ;) – PeterM 2010-05-14 06:30:09

+0

哇! Ierusalimschy先生,歡迎來到StackOverflow! – 2010-05-14 08:15:46

2

關鍵的一句是

這是可能實現延續傳遞風格

計劃(重點煤礦。)你可以通過服用常規的「直式」程序做到這一點並通過名爲CPS變換的程序轉換將它們轉換爲延續傳球風格(CPS)。關鍵是call/cc的CPS轉換是一個簡單的功能。

這對程序員來說不實用。的CPS轉換有兩種用途:

  • 至於學習語言功能理論的想法,尤其是控制運營商
  • 由於在使用CPS作爲中間語言的編譯器一通

你不我不想在Lua代碼上做任何接近CPS轉換的地方,特別是不需要手動轉換。

+2

您可能不想使用CPS編寫完整的應用程序,但以這種方式實現單個算法來解決子問題是完全實用的。 – sigfpe 2010-05-18 17:06:12

+0

* call/cc的CPS轉換是一個簡單的函數* - 小心! call/cc可以通過一個簡單的函數在CPS轉換的目標中定義,但它不是任何事情的CPS轉換,因爲它不通過調用它的繼續而返回。 – 2012-03-22 11:58:51

+0

問題是'如何'而不是'應該'。 – 2016-12-07 10:02:27

7

在Lua回答關於呼叫/ cc計劃的問題:Lua沒有呼叫/ cc的計劃。捕獲延續要麼太昂貴,要麼需要一些遠遠超出Lua編譯器所能做到的代碼。還有一個問題,即Lua延續可能包含C中的部分。然而,使用協程,我們可以在Lua中實現call/cc1(一次延續)。這對於延續的許多用途來說已經足夠了。

+0

我可以理解。任何coroutine.clone的計劃,然後,就像Mike Pall在我的原始文章中的鏈接中執行的計劃一樣? – PeterM 2010-05-15 00:08:58

+0

有關Lua中的callcc工作示例,使用實現coroutine.clone的修改過的Lua,請參閱http://github.com/torus/lua-call-cc/blob/master/callcc.lua。我很快就會嘗試。 :) – PeterM 2010-05-15 16:37:14

-2

這裏是我的cps轉換計劃,只是傳遞你想要轉換的每個功能。

(define (cps-convert function . functions) 
    # Since "help" is called at 2 different places... 
    (define (help) (error "syntax: (cps-convert f1 f2 ...)")) 
    # Single function converter 
    (define (convert func) 
    # "name" contains the function's name prefixed with "cps-" 
    (let ([name (string->symbol 
          (string-append "cps-" (symbol->string func)))]) 
     # Dirty hack to define "cps-*" in the global environment 
    `(eval '(begin 
        # Necessary to prevent the function from being evaluated 
        (define ,name #f) 
           # Magic 
        (set! ,name (lambda (k . args) (k (func args))))) 
       # Global environment 
       (interaction-environment)))) 
    # Prerequisite... Call help if condition not met 
    (if (symbol? function) 
     # function is a symbol 
     (cond 
     # If there is only one function to convert 
     [(null? functions) (convert function)] 
     # Else ensure every other "functions" are symbols and convert each 
     [(every symbol? functions) (apply convert function functions)] 
     # Oops! Condition not met! 
     [else (help)]) 
     # Else clause from previous "if" 
     (help))) 
+0

-1問題是針對Lua。 – BMitch 2011-11-21 17:23:10

+0

這與問題無關。 – 2016-12-07 10:01:08