当前位置:  开发笔记 > 后端 > 正文

寻找延续的"真实"用法的例子

如何解决《寻找延续的"真实"用法的例子》经验,为你挑选了6个好方法。

我正在努力掌握延续的概念,我在维基百科的文章中找到了几个像这样的小教学例子:

(define the-continuation #f)

(define (test)
  (let ((i 0))
    ; call/cc calls its first function argument, passing 
    ; a continuation variable representing this point in
    ; the program as the argument to that function. 
    ;
    ; In this case, the function argument assigns that
    ; continuation to the variable the-continuation. 
    ;
    (call/cc (lambda (k) (set! the-continuation k)))
    ;
    ; The next time the-continuation is called, we start here.
    (set! i (+ i 1))
    i))

我理解这个小函数的作用,但是我看不出任何明显的应用.虽然我不希望很快在我的代码中使用延续,但我希望我知道一些它们可能适合的情况.

所以我正在寻找更多有用的代码示例,这些代码示例可以为程序员提供什么延续.

干杯!



1> sven..:

在Algo和Data II中,我们一直使用这些来从(长)函数"退出"或"返回"

例如,用于遍历树的BFS算法实现如下:

(define (BFS graph root-discovered node-discovered edge-discovered edge-bumped . nodes)
  (define visited (make-vector (graph.order graph) #f))
  (define q (queue.new))
  (define exit ())
  (define (BFS-tree node)
    (if (node-discovered node)
      (exit node))
    (graph.map-edges
     graph
     node
     (lambda (node2)
       (cond ((not (vector-ref visited node2))
              (when (edge-discovered node node2)
                (vector-set! visited node2 #t)
                (queue.enqueue! q node2)))
             (else
              (edge-bumped node node2)))))
    (if (not (queue.empty? q))
      (BFS-tree (queue.serve! q))))

  (call-with-current-continuation
   (lambda (my-future)
     (set! exit my-future)
     (cond ((null? nodes)
            (graph.map-nodes
             graph
             (lambda (node)
               (when (not (vector-ref visited node))
                 (vector-set! visited node #t)
                 (root-discovered node)
                 (BFS-tree node)))))
           (else
            (let loop-nodes
              ((node-list (car nodes)))
              (vector-set! visited (car node-list) #t)
              (root-discovered (car node-list))
              (BFS-tree (car node-list))
              (if (not (null? (cdr node-list)))
                (loop-nodes (cdr node-list)))))))))

如您所见,当节点发现的函数返回true时,算法将退出:

    (if (node-discovered node)
      (exit node))

该函数还将给出"返回值":'node'

为什么函数退出,是因为这句话:

(call-with-current-continuation
       (lambda (my-future)
         (set! exit my-future)

当我们使用exit时,它将返回执行前的状态,清空调用堆栈并返回你给它的值.

基本上,call-cc用于(这里)跳出递归函数,而不是等待整个递归自行结束(在进行大量计算工作时这可能非常昂贵)

另一个与call-cc做同样的小例子:

(define (connected? g node1 node2)
  (define visited (make-vector (graph.order g) #f))
  (define return ())
  (define (connected-rec x y)
    (if (eq? x y)
      (return #t))
    (vector-set! visited x #t)
    (graph.map-edges g
                     x
                     (lambda (t)
                       (if (not (vector-ref visited t))
                         (connected-rec t y)))))
  (call-with-current-continuation
   (lambda (future)
     (set! return future)
     (connected-rec node1 node2)
     (return #f))))



2> Pat..:

海滨:

主页

维基百科页面



3> Sébastien Ro..:

@拍

海滨

是的,Seaside就是一个很好的例子.我快速浏览了它的代码,发现这条消息说明了在Web上以一种看似有状态的方式在组件之间传递控制.

WAComponent >> call: aComponent
    "Pass control from the receiver to aComponent. The receiver will be
    temporarily replaced with aComponent. Code can return from here later
    on by sending #answer: to aComponent."

    ^ AnswerContinuation currentDo: [ :cc |
        self show: aComponent onAnswer: cc.
        WARenderNotification raiseSignal ]

很好!



4> Jonathan Ark..:

我建立了自己的单元测试软件.在执行测试之前,我在执行测试之前存储延续,然后在失败时,我(可选)告诉方案解释器进入调试模式,并重新调用延续.这样我就可以轻松地逐步完成有问题的代码.

如果您的continuation是可序列化的,那么您还可以存储应用程序失败,然后重新调用它们以获取有关变量值,堆栈跟踪等的详细信息.



5> Dave Webb..:

某些Web服务器和Web框架使用Continuations来存储会话信息.为每个会话创建一个continuation对象,然后由会话中的每个请求使用.

这里有一篇关于这种方法的文章.



6> Sébastien Ro..:

我来到了防空火炮的实现,amb运营商在这个职位从http://www.randomhacks.net,使用延续.

这是操作amb员的作用:

# amb will (appear to) choose values
# for x and y that prevent future
# trouble.
x = amb 1, 2, 3
y = amb 4, 5, 6

# Ooops! If x*y isn't 8, amb would
# get angry.  You wouldn't like
# amb when it's angry.
amb if x*y != 8

# Sure enough, x is 2 and y is 4.
puts x, y 

这是帖子的实现:

# A list of places we can "rewind" to
# if we encounter amb with no
# arguments.
$backtrack_points = []

# Rewind to our most recent backtrack
# point.
def backtrack
  if $backtrack_points.empty?
    raise "Can't backtrack"
  else
    $backtrack_points.pop.call
  end
end

# Recursive implementation of the
# amb operator.
def amb *choices
  # Fail if we have no arguments.
  backtrack if choices.empty?
  callcc {|cc|
    # cc contains the "current
    # continuation".  When called,
    # it will make the program
    # rewind to the end of this block.
    $backtrack_points.push cc

    # Return our first argument.
    return choices[0]
  }

  # We only get here if we backtrack
  # using the stored value of cc,
  # above.  We call amb recursively
  # with the arguments we didn't use.
  amb *choices[1...choices.length]
end

# Backtracking beyond a call to cut
# is strictly forbidden.
def cut
  $backtrack_points = []
end

我喜欢amb!

推荐阅读
mobiledu2402852357
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有