8.16
Goto
(require typed/goto) | package: typed-goto |
1 Overview
This package provides label and goto constructs that simulate jump using call/cc.
2 API Reference
procedure
k : continuation?
Sets current continuation.
procedure
(label [prompt-tag]) → continuation?
prompt-tag : continuation-prompt-tag? = (default-continuation-prompt-tag)
Gets current continuation.
(define (label [prompt-tag (default-continuation-prompt-tag)]) (call/cc goto prompt-tag))
procedure
(current-continuation k) → none/c k : continuation?
(define current-continuation (case-λ [() (label)] [(k) (goto k)]))
procedure
(cc) → continuation?
(cc k) → none/c k : continuation?
The cc binding is an alias for current-continuation.
(define-type (Goto a) (∪ a (→ a Nothing)))
Is the fixed point of Goto.
(define-type Label (Goto Label))
3 Examples
3.1 Loop
(let ([x 0]) (define loop (label)) (set! x (add1 x)) (when (< x 7) (goto loop)) (displayln x))
3.2 Yin-Yang Puzzle
(let ([yin (current-continuation)]) (display #\@) (let ([yang (current-continuation)]) (display #\*) (yin yang)))
((begin0 (cc) (display #\@)) (begin0 (cc) (display #\*)))
3.3 Call with Current Continuation
(define (call/cc proc) (define tag 0) (define k (call-with-values cc const*)) (case/eq tag [(0) (set! tag 1) (proc (k))] [(1) (k)]))
3.4 Light-Weight Process
(let ([lwp-queue (make-queue)]) (define (start) (when (non-empty-queue? lwp-queue) (goto (dequeue! lwp-queue)))) (define (lwp-enqueue! break continue) (define first? #t) (define l (label)) (case/eq first? [(#t) (set! first? #f) (enqueue! lwp-queue l) (break)] [(#f) (continue)])) (define (pause) (lwp-enqueue! start void)) (define (lwp thk) (lwp-enqueue! void (λ () (thk) (start)))) (lwp (λ () (goto (begin0 (label) (pause) (display #\h))))) (lwp (λ () (goto (begin0 (label) (pause) (display #\e))))) (lwp (λ () (goto (begin0 (label) (pause) (display #\y))))) (lwp (λ () (goto (begin0 (label) (pause) (display #\!))))) (lwp (λ () (goto (begin0 (label) (pause) (newline))))) (start))
3.5 Ambiguous Operator
(let ([task* '()]) (define (fail) (if (null? task*) (error "Amb tree exhausted") (goto (car task*)))) (define (amb* . alt*) (define first? #t) (define task (label)) (when (null? alt*) (fail)) (when first? (set! first? #f) (set! task* (cons task task*))) (define alt (car alt*)) (set! alt* (cdr alt*)) (when (null? alt*) (set! task* (cdr task*))) (alt)) (define-syntax-rule (amb exp* ...) (amb* (λ () exp*) ...)) (let ([w-1 (amb "the" "that" "a")] [w-2 (amb "frog" "elephant" "thing")] [w-3 (amb "walked" "treaded" "grows")] [w-4 (amb "slowly" "quickly")]) (define (joins? left right) (equal? (string-ref left (sub1 (string-length left))) (string-ref right 0))) (unless (joins? w-1 w-2) (amb)) (unless (joins? w-2 w-3) (amb)) (unless (joins? w-3 w-4) (amb)) (list w-1 w-2 w-3 w-4)))