В 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))))