2014-02-18 24 views
0

在過去的幾天裏,我一直在玩弄計劃(特別是詭計)的延續,並且對於某些函數的結果感到有點困惑並且想知道是否任何人都可以解釋到底發生了什麼。計劃:如何使用call/cc進行回溯

有一個名爲(get-token)將在一個給定的文件檢索發現旁邊標記功能。例如,如果接下來的3個標記是「a」,「b」和「c」,調用(get-token)將在第一次調用時返回「a」,第二次調用時返回「b」和「c」第三次被稱爲。

我想要做的是有一個函數(peek-token),將調用(get-token),返回令牌,然後返回到調用(get-token)函數之前的狀態。我嘗試了許多不同的方法來實現這一結果,和我目前擁有的是:

;; make things a little easier to write 
(define-syntax bind/cc 
    (syntax-rules() 
    ((bind/cc var . body) 
    (call/cc (lambda (var) . body))))) 

;; function should return next token and then 
;; revert to previous state 
(define (peek-token) 
    (bind/cc return 
      (let ((token (get-token))) 
      (return token)))) 

我現在如何的理解,bind/cc將在第一return保存的延續,然後執行以下代碼塊。然後當return再次被擊中時,程序跳回到連續被綁定的位置,並且結果給出token值。

然而,當我運行上面的函數的結果是完全一樣的原始(get-token)功能。

我會很感激,如果任何人都可以解釋我要去的地方錯了,或者表達一種更好的方法來獲得相同的結果(我知道有些人討厭去呼叫/立方厘米的方式)。

回答

4

亂砍馬克·吐溫錯誤引用到片:的call/cc的能力的報告嚴重誇大了。

更具體地,call/cc捕獲呼叫狀態,不編程狀態。這意味着它會捕獲有關調用延續時代碼流向何處的信息。它還對變量捕獲的信息,特別是,如果你的get-token通過set!婷變量中保存了它的迭代狀態,這是不會當你調用你的持續恢復。

事實上,你的(call/cc (lambda (k) (let ((token (get-token))) (k token))))表達式應該相同的行爲簡單地(get-token);這兩個表達式之間不應該有明顯的差異。

+0

非常感謝你的幫助。我最終將'(peek-token)'函數放在我的掃描器文件中,並且只是跟蹤文件指針,以便我可以從中重新讀取令牌。出於好奇,你是否知道一種方法來捕獲任一方案或CL中的實際程序狀態?或者從來沒有真正需要這個? – vikingsheepman

+0

除非我弄錯了形式'(call-cc(lambda(k)...(k x)))'與'(begin ... x)'完全相同的任何形式。 – jozefg

+0

@jozefg非常多,假設這是繼續使用的唯一地方。 –