簡體   English   中英

計划延續 - 需要解釋

[英]scheme continuations -need explanation

以下示例涉及跳轉到延續和退出。 有人可以解釋功能的流程。 我圍繞延續移動了一圈,並且不知道函數的入口和出口點。

(define (prod-iterator lst)
  (letrec ((return-result empty)
        (resume-visit (lambda (dummy) (process-list lst 1)))
        (process-list
         (lambda (lst p)
           (if (empty? lst)
               (begin
                 (set! resume-visit (lambda (dummy) 0))
                 (return-result p))
               (if (= 0 (first lst))
                   (begin
                     (call/cc ; Want to continue here after delivering result     
                      (lambda (k)
                        (set! resume-visit k)
                        (return-result p)))
                     (process-list (rest lst) 1))
                   (process-list (rest lst) (* p (first lst))))))))
    (lambda ()
      (call/cc
       (lambda (k)
         (set! return-result k)
         (resume-visit 'dummy))))))

(define iter (prod-iterator '(1 2 3 0 4 5 6 0 7 0 0 8 9)))
(iter) ; 6                                                                        
(iter) ; 120                                                                      
(iter) ; 7                                                                        
(iter) ; 1                                                                        
(iter) ; 72                                                                       
(iter) ; 0                                                                        
(iter) ; 0

謝謝。

該過程迭代一個列表,將非零成員相乘,並在每次找到零時返回結果。 Resume-visit存儲繼續處理列表的其余部分, return-result繼續迭代器的調用站點。 在開始時,定義resume-visit來處理整個列表。 每一個零被發現時,繼續被捕獲,其中,當被調用執行(process-list (rest lst) 1)的任何值lst在當時。 當列表用盡時, resume-visit設置為虛擬過程。 而且,每次程序調用iter ,它都會執行以下操作:

(call/cc
   (lambda (k)
     (set! return-result k)
     (resume-visit 'dummy)))

也就是說,它捕獲調用者的延續,調用它會向調用者返回一個值。 存儲繼續,程序跳轉以處理列表的其余部分。 當過程調用resume-visit ,進入循環,當調用return-result時,退出循環。

如果我們想更詳細地檢查process-list ,我們假設列表是非空的。 該過程采用基本遞歸,累積結果直到找到零。 此時, p是累計值, lst是包含零的列表。 當我們有一個像(begin (call/cc (lambda (k) first)) rest)的構造時,我們首先執行first表達式,其中k綁定到一個continuation。 它是一個在調用時執行rest表達式的過程。 在這種情況下,存儲該延續並調用另一個繼續,它將累積的結果p返回給iter的調用者。 將在下次調用iter調用該延續,然后循環繼續執行列表的其余部分。 這是延續的要點,其他一切都是基本的遞歸。

你需要記住的是,對(call/cc f)將把作為參數傳遞的函數f應用於call/cc到當前的continuation。 如果在函數f內部使用某個參數a調用該延續,則執行將轉到相應的call/cc ,並且參數a將作為該call/cc的返回值返回。

您的程序在變量return-result存儲“ call/cc iter call/cc in iter ”的繼續,並開始處理列表。 它在遇到前0之前將列表的前3個非零元素相乘。當它看到0時,繼續“處理列表元素0”存儲在resume-visit ,值p返回到continuation return-result通過調用(return-result p) 此調用將使執行返回到itercall/cc ,並且該call/cc返回p的傳遞值。 所以你看到第一個輸出6。

其余的對iter調用是相似的,並且會使執行在這兩個延續之間來回傳遞。 手動分析可能有點大腦扭曲,您必須知道恢復延續時的執行上下文。

你可以這樣做:

(define (prod-iter lst) (fold * 1 (remove zero? lst)))

......即使它只能通過一次遍歷也能表現得更好。

對於延續,召回(雙關語)所有呼叫/ cc所做的是等待以這種方式應用“k”:

(call/cc (lambda (k) (k 'return-value)))
  => return-value

這里的訣竅是你可以讓call / cc返回它自己的continuation,這樣它就可以在call / cc返回之后應用到別處:

;; returns twice; once to get bound to k, the other to return blah
(let ([k (call/cc (lambda (k) k))]) ;; k gets bound to a continuation
  (k 'blah)) ;; k returns here
  => blah

這樣可以通過將延遲保存在變量中來使連續返回多次。 Continuations只返回它們應用的值。

閉包是在參數與它們綁定之前攜帶其環境變量的函數。 他們是普通的lambdas。

延續傳遞樣式是一種將閉包作為參數傳遞以便稍后應用的方法。 我們說這些閉包參數是延續的。 這里是來自我的數獨生成器/解算器的當前代碼的一半,作為示例演示了延續傳遞樣式如何簡化算法:

#| the grid is internally represented as a vector of 81 numbers
example: (make-vector 81 0)

this builds a list of indexes |#
(define (cell n) (list (+ (* (car 9) (cadr n))))
(define (row n) (iota 9 (* n 9)))
(define (column n) (iota 9 n 9))
(define (region n)
  (let* ([end (+ (* (floor-quotient n 3) 27)
                 (* (remainder n 3) 3))]
         [i (+ end 21)])
    (do ([i i
          (- i (if (zero? (remainder i 3)) 7 1))]
         [ls '() (cons (vector-ref *grid* i) ls)])
      ((= i end) ls))))

#| f is the continuation

usage examples:
(grid-ref *grid* row 0)
(grid-set! *grid* region 7) |#
(define (grid-ref g f n)
  (map (lambda (i) (vector-ref g i)) (f n)))
(define (grid-set! g f n ls)
  (for-each (lambda (i x) (vector-set! g i x))
    (f n) ls))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM