(aux continuation classic): classic continuation operators
Classic continuation operators
Ported from on-scheme's continuations.scm, after The Seasoned Schemer.
Implementation
(module
(aux continuation classic)
*
(import
scheme
(chicken base)
(chicken continuation)
(only (chicken fixnum) fx+ fx- fx<)
(only srfi-1 last)
(aux base)
(aux continuation))
(define (continuation-rewind! winds n)
(cond ((eq? ##sys#dynamic-winds winds) (void))
((fx< n 0)
(continuation-rewind! (cdr winds) (fx+ n 1))
((car (car winds)))
(set! ##sys#dynamic-winds winds))
(else
(let1 (after (cdr (car ##sys#dynamic-winds)))
(set! ##sys#dynamic-winds (cdr ##sys#dynamic-winds))
(after)
(continuation-rewind! winds (fx- n 1))))))
(define continuation->λ
(λ (raw)
(##sys#check-structure raw 'continuation 'continuation->λ)
(let1 (winds (##sys#slot raw 2))
(λ args
(unless
(eq? ##sys#dynamic-winds winds)
(continuation-rewind!
winds
(fx- (length ##sys#dynamic-winds) (length winds))))
(apply continuation-return raw args)))))
(define-syntax-rule
(letcc/raw (raw hop) body ...)
(continuation-capture
(λ (raw) (let1 (hop (continuation->λ raw)) body ...))))
(define (apply/cc f . args)
(letcc k (apply f (append (butlast args) (last args) (list k)))))
(define-syntax
escapecc
(syntax-rules
(else =>)
((escapecc (out α) (else β)) (letcc out α β))
((escapecc (out α) (=> f)) (letcc out (let1 (result α) (f result))))))
(define-syntax
trycc/named
(syntax-rules
(else =>)
((trycc/named (skip α) ... (else β))
(letcc success (letcc skip (success α)) ... β))
((trycc/named (skip α) ... (else => f))
(letcc success
(let1 (outputs (list (letcc skip (success α)) ...))
(f outputs))))))
(define-syntax-rule (set/cc! v) (set! v (letcc/raw (raw hop) hop)))
(define-syntax
cond/cc
(syntax-rules
(else)
((cond/cc (pred? handling) ... (else recv))
(letcc/raw
(cont hop)
(cond ((continuation? cont) (recv hop))
((pred? cont) (handling cont))
...
(else (error "Contract violation")))))))
(define current-continuation/cont
(τ (continuation-capture (λ (cont) ((continuation->λ cont) cont)))))
(define current-continuation/λ
(τ (continuation-capture (compose Φ continuation->λ))))
(define-syntax-rule
(letcc/escaper escaper body ...)
((letcc top
(let1 (escaper (λ (proc) (λ args (top (τ (apply proc args))))))
(τ body ...))))))
test/letcc: pass
(define (test/letcc _)
(⊦= 1 (letcc hop 1))
(⊦= 1 (letcc hop (hop 1)))
(⊦= 1 (letcc hop (add1 (hop 1))))
(⊦= 10 (+ 9 (letcc hop (add1 (hop 1)))))
(⊦= 1 (letcc/raw (raw hop) 1))
(⊦= 1 (letcc/raw (raw hop) (hop 1)))
(⊦= 1 (letcc/raw (raw hop) (add1 (hop 1))))
(⊦= 10 (+ 9 (letcc/raw (raw hop) (add1 (hop 1))))))
((eta 0.0) (memory #(12582912 2195640 1048576)) (stdout "") (stderr ""))
test/trycc/named: pass
(define (test/trycc/named _)
(let ((identity-applicative&return (λ (x skip) x))
(identity-applicative&skip (λ (x skip) (skip 'discard))))
(⊦= 1
(trycc/named
(skip (identity-applicative&return 1 skip))
(else (eternity))))
(⊦= 2 (trycc/named (skip (identity-applicative&skip 1 skip)) (else 2)))
(⊦= '(1)
(trycc/named
(skip1 (list 1))
(skip2 'useless)
(else 'even-more-useless)))
(⊦= '(2)
(trycc/named
(skip1 (list 1 (skip1 'discard)))
(skip2 (list 2))
(else 'useless)))
(⊦= '(3)
(trycc/named
(skip1 (list 1 (skip1 'discard)))
(skip2 (list 2 (skip2 'discard)))
(else (list 3))))))
((eta 0.0) (memory #(12582912 2197104 1048576)) (stdout "") (stderr ""))
test/trycc/named/=>: pass
(define (test/trycc/named/=> _)
(⊦= '(discard discard)
(trycc/named
(skip1 (list 1 (skip1 'discard)))
(skip2 (list 2 (skip2 'discard)))
(else => identity)))
(⊦= '(1)
(trycc/named
(skip1 (list 1))
(skip2 (list 2 (skip2 'discard)))
(else => identity))))
((eta 0.0) (memory #(12582912 2196152 1048576)) (stdout "") (stderr ""))
test/letcc/output: pass
(define (test/letcc/output _)
(⊦= "I got here\nThis string was passed to the continuation.\n"
(with-output-to-string
(τ (display
(letcc cont
(display "I got here\n")
(cont "This string was passed to the continuation.\n")
(display "...but not here")))))))
((eta 0.0) (memory #(12582912 2200232 1048576)) (stdout "") (stderr ""))
test/set/cc!: pass
(define (test/set/cc! _)
(let1 (port (open-output-string))
(⊨ (condition-case
(begin
(let ((start #f))
(unless start (set/cc! start))
(display "Going to invoke `(start)`\n" port)
(start))
#f)
((exn) #t)))
(⊦= "Going to invoke `(start)`\nGoing to invoke `(start)`\n"
(get-output-string port))))
((eta 0.0) (memory #(12582912 2205760 1048576)) (stdout "") (stderr ""))
test/cond/cc: pass
(define (test/cond/cc _)
(⊦= 3 (cond/cc (number? add1) (else (λ (cont) (+ 2 (cont 3)))))))
((eta 0.0) (memory #(12582912 2209600 1048576)) (stdout "") (stderr ""))
test/letcc/raw: pass
(define (test/letcc/raw _)
(⊦= 5
(let ((start #f))
(letcc/raw
(cont λ)
(unless start (set! start λ))
(cond ((continuation? cont) (λ 3))
((number? cont) (add1 cont))
(else (error "e")))
(start)
(λ 7))
5)))
((eta 0.0) (memory #(12582912 2213320 1048576)) (stdout "") (stderr ""))
test/escapecc: pass
(define (test/escapecc _)
(let ((leftmost
(λ (l)
(escapecc
(hop (let L ((ll l))
(cond ((null? ll) '(no symbol here))
((symbol? (car ll)) (hop (car ll)))
(else (begin (L (car ll)) (L (cdr ll)))))))
(else l)))))
(⊦= 'a (leftmost '(((a) b) (c d))))
(⊦= 'a (leftmost '(((a) ()) () (e))))
(⊦= '((() ())) (leftmost '((() ())))))
(⊦= 3 (escapecc (out (+ 1 (out 3))) (=> add1)))
(⊦= 5 (escapecc (out (+ 1 3)) (=> add1)))
(⊦= 'done (escapecc (out (+ 1 3)) (else 'done))))
((eta 0.0) (memory #(12582912 2204656 1048576)) (stdout "") (stderr ""))
test/apply/cc: pass
(define (test/apply/cc _)
(⊦= '(1 2 3 4) (apply/cc (λ (a b c d k) (list a b c d)) 1 2 '(3 4)))
(⊦= 'escaped (apply/cc (λ (a b k) (cons a (k 'escaped))) '(1 2)))
(⊦= '(1 . 2) (apply/cc (λ (a b k) (cons a b)) 1 '(2)))
(⊦= 'no (apply/cc (λ (k) (+ 1 (k 'no))) '())))
((eta 0.0) (memory #(12582912 2207856 1048576)) (stdout "") (stderr ""))
test/continuation->λ: pass
(define (test/continuation->λ _)
(⊦= '(1 2)
(call-with-values
(τ (continuation-capture (λ (raw) ((continuation->λ raw) 1 2))))
list))
(⊦= 3
(+ 1 (continuation-capture (λ (raw) (* 10 ((continuation->λ raw) 2)))))))
((eta 0.0) (memory #(12582912 2208856 1048576)) (stdout "") (stderr ""))
test/continuation->λ/dynamic-wind: pass
(define (test/continuation->λ/dynamic-wind _)
(define q (make-parameter 'outer))
(define wlog '())
(⊦= '((2 inner) (1 inner) (0 inner))
(let ((n 2) (acc '()) (k #f))
(parameterize
((q 'inner))
(dynamic-wind
(τ (push! 'in wlog))
(τ (letcc/raw (raw hop) (set! k hop)) (push! (list n (q)) acc))
(τ (push! 'out wlog))))
(unless (zero? n) (set! n (sub1 n)) (k 'again))
(reverse acc)))
(⊦= 'outer (q))
(⊦= '(in out in out in out) (reverse wlog)))
((eta 0.0) (memory #(12582912 2209816 1048576)) (stdout "") (stderr ""))
test/current-continuation: pass
(define (test/current-continuation _)
(⊨ (continuation? (current-continuation/cont)))
(⊨ (procedure? (current-continuation/λ)))
(⊦= '(0 1 2 3)
(let ((n 3) (acc '()))
(let1 (k (current-continuation/λ))
(push! n acc)
(unless (zero? n) (set! n (sub1 n)) (k k)))
acc))
(⊦= '(0 1 2 3)
(let ((n 3) (acc '()))
(let1 (c (current-continuation/cont))
(push! n acc)
(unless (zero? n) (set! n (sub1 n)) (continuation-return c c)))
acc)))
((eta 0.0) (memory #(12582912 2209856 1048576)) (stdout "") (stderr ""))
test/letcc/escaper: pass
(define (test/letcc/escaper _)
(⊦= 10 (letcc/escaper escaper (+ ((escaper *) 5 2) 3)))
(⊦= 15
(letcc/escaper
escaper
(+ ((escaper (λ (x) (- ((escaper *) x 3) 7))) 5) 4)))
(⊦= -1 (letcc/escaper escaper ((escaper add1) ((escaper sub1) 0))))
(⊦= '(3)
(letcc/escaper
escaper
(let ((escape-cons (escaper cons)))
(escape-cons 1 (escape-cons 2 (escape-cons 3 '()))))))
(⊦= '(a b d)
(letcc/escaper
escaper
(let ((receiver (escaper (λ (proc) (cons 'c (proc (list 'd)))))))
(cons 'a (cons 'b (call-with-current-continuation receiver)))))))
((eta 0.0) (memory #(12582912 2212008 1048576)) (stdout "") (stderr ""))
(aux continuation classic): escapers, after Scheme and the Art of Programming
Escape procedures and call/cc
Exercises of chapter 16 of Springer and Friedman, Scheme and the Art of Programming, on contexts, escape procedures and call/cc.
test/contexts: pass
(define (test/contexts _)
(⊦= (+ 3 (* 4 (+ 5 6))) ((λ (▢) (+ 3 (* 4 ▢))) (+ 5 6)))
(⊦= 47 ((λ (▢) (+ 3 (* 4 ▢))) (+ 5 6)))
(⊦= (letrec ((sum+n (λ (n) (if (zero? n) 1 (+ (add1 n) (sum+n (sub1 n)))))))
(* 10 (sum+n 5)))
((λ (▢) (* 10 (+ 6 (+ 5 (+ ▢ (+ 3 (+ 2 1))))))) (add1 3)))
(⊦= 210 ((λ (▢) (* 10 (+ 6 (+ 5 (+ ▢ (+ 3 (+ 2 1))))))) (add1 3)))
(let* ((out (open-output-string))
(v (begin
(display 0 out)
(let ((n 1))
(if (zero? n)
(display (+ 3 (* 4 (+ 5 6))) out)
(display (* (+ (* 3 4) 5) 2) out))
(set! n (+ n 2))
n))))
(⊦= "034" (get-output-string out))
(⊦= 3 v))
(let* ((out (open-output-string))
(n 1)
(context
(λ (▢)
(begin
(display 0 out)
(display (* (+ ▢ 5) 2) out)
(set! n (+ n 2))
n))))
(⊦= 3 (context (* 3 4)))
(⊦= 5 (context (* 3 4)))
(⊦= "034034" (get-output-string out))))
((eta 0.0) (memory #(12582912 2461072 1048576)) (stdout "") (stderr ""))
test/escaper/first: pass
(define (test/escaper/first _)
(⊦= 10
(letcc/escaper
escaper
(let ((escape-* (escaper *))) (+ (escape-* 5 2) 3)))))
((eta 0.0) (memory #(12582912 2464848 1048576)) (stdout "") (stderr ""))
test/escaper: pass
(define (test/escaper _)
(⊦= 10 (letcc/escaper escaper (+ ((escaper *) 5 2) 3)))
(⊦= 8 (letcc/escaper escaper (+ ((escaper (λ (x) (- (* x 3) 7))) 5) 4)))
(⊦= 8
(letcc/escaper
escaper
(+ ((escaper (λ (x) ((escaper -) (* x 3) 7))) 5) 4)))
(⊦= 15 ((λ (x) (* x 3)) 5))
(⊦= 15
(letcc/escaper
escaper
(+ ((escaper (λ (x) (- ((escaper *) x 3) 7))) 5) 4)))
(⊦= 15
(letcc/escaper
escaper
(+ ((escaper (λ (x) ((escaper -) ((escaper *) x 3) 7))) 5) 4))))
((eta 0.0) (memory #(12582912 2465752 1048576)) (stdout "") (stderr ""))
test/escaper/abandons: pass
(define (test/escaper/abandons _)
(⊦= 8
(letcc/escaper escaper (/ (+ ((escaper (λ (x) (- (* x 3) 7))) 5) 4) 2)))
(⊦= -1 (letcc/escaper escaper ((escaper add1) ((escaper sub1) 0))))
(⊦= '(3)
(letcc/escaper
escaper
(let ((escape-cons (escaper cons)))
(escape-cons 1 (escape-cons 2 (escape-cons 3 '()))))))
(⊦= "reset invoked"
(with-output-to-string
(τ (letcc/escaper
escaper
(let ((reset (λ ()
(let ((escape
(escaper (λ () (display "reset invoked")))))
(escape)))))
(cons 1 (reset)))))))
(⊨ (void? (letcc/escaper
escaper
(let ((reset (λ ()
(let ((escape (escaper (λ () (void))))) (escape)))))
(cons 1 (reset))))))
(⊦= '(2)
(letcc/escaper
escaper
(let ((reset (λ () ((escaper (λ () '(2))))))) (cons 1 (reset))))))
((eta 0.0) (memory #(12582912 2467232 1048576)) (stdout "") (stderr ""))
test/receiver/escaper: pass
(define (test/receiver/escaper _)
(⊦= 27
(letcc/escaper
escaper
(let ((receiver (λ (continuation) 6)) (context (λ (▢) (+ 3 (* 4 ▢)))))
(+ 3 (* 4 (receiver (escaper context)))))))
(⊦= 27
(letcc/escaper
escaper
(let ((receiver (λ (continuation) (continuation 6)))
(context (λ (▢) (+ 3 (* 4 ▢)))))
(+ 3 (* 4 (receiver (escaper context)))))))
(⊦= 27
(letcc/escaper
escaper
(let ((receiver (λ (continuation) (+ 2 (continuation 6))))
(context (λ (▢) (+ 3 (* 4 ▢)))))
(+ 3 (* 4 (receiver (escaper context))))))))
((eta 0.0) (memory #(12582912 2468368 1048576)) (stdout "") (stderr ""))
test/receiver/call/cc: pass
(define (test/receiver/call/cc _)
(⊦= 27
(let ((receiver (λ (continuation) 6))) (+ 3 (* 4 (call/cc receiver)))))
(⊦= 27
(let ((receiver (λ (continuation) (continuation 6))))
(+ 3 (* 4 (call/cc receiver)))))
(⊦= 27
(let ((receiver (λ (continuation) (+ 2 (continuation 6)))))
(+ 3 (* 4 (call/cc receiver))))))
((eta 0.0) (memory #(12582912 2471544 1048576)) (stdout "") (stderr ""))
test/16.9: pass
(define (test/16.9 _)
(⊦= -22
(letcc/escaper
escaper
(let ((context (λ (▢) (- 3 (* 5 ▢))))
(receiver (λ (continuation) (continuation 5))))
(- 3 (* 5 (receiver (escaper context)))))))
(⊦= -22
(let ((receiver (λ (continuation) (continuation 5))))
(- 3 (* 5 (call/cc receiver)))))
(⊦= -22
(letcc/escaper
escaper
(let ((context (λ (▢) (- 3 (* 5 ▢)))) (receiver (λ (continuation) 5)))
(- 3 (* 5 (receiver (escaper context)))))))
(⊦= -22
(let ((receiver (λ (continuation) 5))) (- 3 (* 5 (call/cc receiver)))))
(⊦= -22
(letcc/escaper
escaper
(let ((context (λ (▢) (- 3 (* 5 ▢))))
(receiver (λ (continuation) (+ 1000 (continuation 5)))))
(- 3 (* 5 (receiver (escaper context)))))))
(⊦= -22
(let ((receiver (λ (continuation) (+ 1000 (continuation 5)))))
(- 3 (* 5 (call/cc receiver))))))
((eta 0.0) (memory #(12582912 2470472 1048576)) (stdout "") (stderr ""))
test/experiment/first: pass
(define (test/experiment/first _)
(let* ((port (open-output-string))
(call (λ (receiver) (receiver (display/return/port port))))
(result (void)))
(set! result ((answer-maker/port port) (call receiver-1)))
(⊦= "(1)(1)" (get-output-string port))
(⊦= '(answer-is 1) result))
(let* ((port (open-output-string)) (result/cc (void)))
(set! result/cc ((answer-maker/port port) (call/cc receiver-1)))
(⊦= "(1)" (get-output-string port))
(⊦= '(answer-is 1) result/cc)))
((eta 0.0) (memory #(12582912 2472152 1048576)) (stdout "") (stderr ""))
test/experiment/second: pass
(define (test/experiment/second _)
(let* ((port (open-output-string))
(call (λ (receiver) (receiver (display/return/port port))))
(result (void)))
(set! result ((answer-maker/port port) (call receiver-2)))
(⊦= "(2)((2))((2))" (get-output-string port))
(⊦= '(answer-is (2)) result))
(let* ((port (open-output-string)) (result/cc (void)))
(set! result/cc ((answer-maker/port port) (call/cc receiver-2)))
(⊦= "(2)" (get-output-string port))
(⊦= '(answer-is 2) result/cc)))
((eta 0.0) (memory #(12582912 2472648 1048576)) (stdout "") (stderr ""))
test/experiment/third: pass
(define (test/experiment/third _)
(let* ((port (open-output-string))
(display/return (display/return/port port))
(call (λ (receiver) (receiver display/return)))
(result (void)))
(set! result ((answer-maker/port port) (call receiver-3)))
(⊦= "(3 #<procedure>)((3 #<procedure>))((3 #<procedure>))"
(procedure-names/normalise (get-output-string port)))
(⊦= `(answer-is (3 ,display/return)) result)
(let1 (mark (string-length (get-output-string port)))
(⊦= '(1000) ((cadr (cadr result)) (list 1000)))
(⊦= "(1000)" (substring (get-output-string port) mark)))
(⊦= `(answer-is (3 ,display/return)) result)))
((eta 0.0) (memory #(12582912 2479112 1048576)) (stdout "") (stderr ""))
test/experiment/third/call/cc: pass
(define (test/experiment/third/call/cc _)
(let* ((phase 0) (port (open-output-string)) (mark 0) (result/cc (void)))
(set! result/cc ((answer-maker/port port) (call/cc receiver-3)))
(set! phase (add1 phase))
(cond ((= phase 1)
(⊦= "(3 #<procedure>)"
(procedure-names/normalise (get-output-string port)))
(⊦= `(answer-is 3 ,(caddr result/cc)) result/cc)
(⊨ (procedure? (caddr result/cc)))
(set! mark (string-length (get-output-string port)))
((caddr result/cc) (list 1000))
(⊭ 'unreachable))
(else
(⊦= 2 phase)
(⊦= "(1000)" (substring (get-output-string port) mark))
(⊦= '(answer-is 1000) result/cc)))))
((eta 0.0) (memory #(12582912 2481144 1048576)) (stdout "") (stderr ""))
test/experiment/fourth: pass
(define (test/experiment/fourth _)
(let* ((port (open-output-string))
(display/return (display/return/port port))
(call (λ (receiver) (receiver display/return)))
(result (void)))
(⊦= 'done
(begin
(set! result ((answer-maker/port port) (call receiver-3)))
'done))
(⊦= "(3 #<procedure>)((3 #<procedure>))((3 #<procedure>))"
(procedure-names/normalise (get-output-string port)))
(⊦= `(answer-is (3 ,display/return)) result)
(let1 (mark (string-length (get-output-string port)))
(⊦= '(1000) ((cadr (cadr result)) (list 1000)))
(⊦= "(1000)" (substring (get-output-string port) mark)))
(⊦= `(answer-is (3 ,display/return)) result)))
((eta 0.0) (memory #(12582912 2482512 1048576)) (stdout "") (stderr ""))
test/experiment/fourth/call/cc: pass
(define (test/experiment/fourth/call/cc _)
(let* ((phase 0) (port (open-output-string)) (mark 0) (result/cc (void)))
(let1 (v (begin
(set! result/cc ((answer-maker/port port) (call/cc receiver-3)))
'done))
(set! phase (add1 phase))
(⊦= 'done v)
(cond ((= phase 1)
(⊦= "(3 #<procedure>)"
(procedure-names/normalise (get-output-string port)))
(⊦= `(answer-is 3 ,(caddr result/cc)) result/cc)
(set! mark (string-length (get-output-string port)))
((caddr result/cc) (list 1000))
(⊭ 'unreachable))
(else
(⊦= 2 phase)
(⊦= "(1000)" (substring (get-output-string port) mark))
(⊦= '(answer-is 1000) result/cc))))))
((eta 0.0) (memory #(12582912 2483672 1048576)) (stdout "") (stderr ""))
test/16.14: pass
(define (test/16.14 _)
(let ((receiver
(λ (continuation)
(if (zero? (pseudo-random-integer 2))
(+ 1000 6)
(continuation 6)))))
(do ((i 0 (add1 i)))
((= i 32))
(⊨ (member? (* (+ (call/cc receiver) 3) 8) '(72 8072)))
(⊨ (member?
(+ (* (+ (call/cc receiver) 3) 8) (* (+ (call/cc receiver) 3) 8))
'(144 8144 16144)))))
(let ((receiver
(λ (continuation)
(continuation
(if (zero? (continuation (pseudo-random-integer 2)))
(+ 1000 6)
6)))))
(do ((i 0 (add1 i)))
((= i 32))
(⊨ (member?
(+ (* (+ (call/cc receiver) 3) 8) (* (+ (call/cc receiver) 3) 8))
'(48 56 64))))))
((eta 0.0) (memory #(12582912 2483896 1048576)) (stdout "") (stderr ""))
test/16.16: pass
(define (test/16.16 _)
(let* ((deep (void))
(map-sub1
(letrec ((M (λ (ls)
(if (null? ls)
(call/cc
(λ (continuation) (set! deep continuation) '()))
(cons (sub1 (car ls)) (M (cdr ls)))))))
M))
(run (λ (ls)
(let ((phase 0) (results '()))
(let1 (v (cons 1000 (map-sub1 ls)))
(push! v results)
(set! phase (add1 phase))
(when (= phase 1) (cons 2000 (deep '(a b c)))))
(reverse results)))))
(⊦= '((1000) (1000 a b c)) (run '()))
(⊦= '((1000 -1) (1000 -1 a b c)) (run '(0)))
(⊦= '((1000 0 -1) (1000 0 -1 a b c)) (run '(1 0)))
(⊦= '((1000 4 3 2 1 0 -1) (1000 4 3 2 1 0 -1 a b c))
(run '(5 4 3 2 1 0)))))
((eta 0.0) (memory #(12582912 2487560 1048576)) (stdout "") (stderr ""))
test/escaper/thunk: pass
(define (test/escaper/thunk _)
(⊦= 7 (letcc/escaper escaper ((escaper (τ (add1 6))))))
(⊦= 7 (letcc/escaper escaper (+ 5 ((escaper (τ (add1 6))))))))
((eta 0.0) (memory #(12582912 2488520 1048576)) (stdout "") (stderr ""))
test/escaper/receiver: pass
(define (test/escaper/receiver _)
(⊦= '(a b d)
(letcc/escaper
escaper
(let ((receiver (escaper (λ (proc) (cons 'c (proc (list 'd)))))))
(cons 'a (cons 'b (call/cc receiver))))))
(⊦= '(c d)
(letcc/escaper
escaper
(let ((receiver (escaper (λ (proc) '(c d)))))
(cons 'a (cons 'b (call/cc receiver))))))
(⊦= '(c d)
(letcc/escaper
new-escaper
(let ((receiver (new-escaper (λ (proc) '(c d)))))
(cons 'a (cons 'b (call/cc receiver)))))))
((eta 0.001) (memory #(12582912 2490248 1048576)) (stdout "") (stderr ""))
test/countdown: pass
(define (test/countdown _)
(let* ((countdown
(λ (n attempt)
(format #t "~%This string will appear only once~%")
(let* ((message
(λ (direction value)
(format
#t
"\t~Aing `attempt` function with value ~A~%"
direction
value)
value))
(pair (message 'exit (attempt (message 'enter n))))
(v (car pair))
(returner (cadr pair)))
(format #t "\tnon-negative number: ~A~%" v)
(if (positive? v)
(returner (list (sub1 v) returner))
(format #t "Blastoff")))))
(v (void)))
(⊦= "\nThis string will appear only once\n\tentering `attempt` function with value 3\n\texiting `attempt` function with value (3 #<procedure>)\n\tnon-negative number: 3\n"
(procedure-names/normalise
(with-output-to-string
(τ (set! v
(let ((attempt
(λ (n)
(let ((receiver (λ (proc) (list n proc))))
(receiver (λ (x) x))))))
(countdown 3 attempt)))))))
(⊦= 2 (car v))
(⊨ (procedure? (cadr v)))
(⊦= "\nThis string will appear only once\n\tentering `attempt` function with value 3\n\texiting `attempt` function with value (3 #<procedure>)\n\tnon-negative number: 3\n\texiting `attempt` function with value (2 #<procedure>)\n\tnon-negative number: 2\n\texiting `attempt` function with value (1 #<procedure>)\n\tnon-negative number: 1\n\texiting `attempt` function with value (0 #<procedure>)\n\tnon-negative number: 0\nBlastoff"
(procedure-names/normalise
(with-output-to-string
(τ (let ((attempt
(λ (n)
(let ((receiver (λ (proc) (list n proc))))
(call/cc receiver)))))
(countdown 3 attempt))))))))
((eta 0.0) (memory #(12582912 2491808 1048576)) (stdout "") (stderr ""))
test/three-phases: pass
(define (test/three-phases _)
(⊦= "beginbeginmiddlebeginend"
(with-output-to-string
(τ (let ((receiver (λ (continuation) (continuation continuation)))
(three-phases
(λ (continuation)
(display 'begin)
(call/cc continuation)
(display 'middle)
(call/cc continuation)
(display 'end))))
(three-phases (call/cc receiver)))))))
((eta 0.0) (memory #(12582912 2496048 1048576)) (stdout "") (stderr ""))
(aux continuation amb): McCarthy’s amb and a SAT solver
McCarthy's amb and a SAT solver
Ported from on-scheme's continuations.scm.
Implementation
(module
(aux continuation classic)
*
(import
scheme
(chicken base)
(chicken continuation)
(only (chicken fixnum) fx+ fx- fx<)
(only srfi-1 last)
(aux base)
(aux continuation))
(define (continuation-rewind! winds n)
(cond ((eq? ##sys#dynamic-winds winds) (void))
((fx< n 0)
(continuation-rewind! (cdr winds) (fx+ n 1))
((car (car winds)))
(set! ##sys#dynamic-winds winds))
(else
(let1 (after (cdr (car ##sys#dynamic-winds)))
(set! ##sys#dynamic-winds (cdr ##sys#dynamic-winds))
(after)
(continuation-rewind! winds (fx- n 1))))))
(define continuation->λ
(λ (raw)
(##sys#check-structure raw 'continuation 'continuation->λ)
(let1 (winds (##sys#slot raw 2))
(λ args
(unless
(eq? ##sys#dynamic-winds winds)
(continuation-rewind!
winds
(fx- (length ##sys#dynamic-winds) (length winds))))
(apply continuation-return raw args)))))
(define-syntax-rule
(letcc/raw (raw hop) body ...)
(continuation-capture
(λ (raw) (let1 (hop (continuation->λ raw)) body ...))))
(define (apply/cc f . args)
(letcc k (apply f (append (butlast args) (last args) (list k)))))
(define-syntax
escapecc
(syntax-rules
(else =>)
((escapecc (out α) (else β)) (letcc out α β))
((escapecc (out α) (=> f)) (letcc out (let1 (result α) (f result))))))
(define-syntax
trycc/named
(syntax-rules
(else =>)
((trycc/named (skip α) ... (else β))
(letcc success (letcc skip (success α)) ... β))
((trycc/named (skip α) ... (else => f))
(letcc success
(let1 (outputs (list (letcc skip (success α)) ...))
(f outputs))))))
(define-syntax-rule (set/cc! v) (set! v (letcc/raw (raw hop) hop)))
(define-syntax
cond/cc
(syntax-rules
(else)
((cond/cc (pred? handling) ... (else recv))
(letcc/raw
(cont hop)
(cond ((continuation? cont) (recv hop))
((pred? cont) (handling cont))
...
(else (error "Contract violation")))))))
(define current-continuation/cont
(τ (continuation-capture (λ (cont) ((continuation->λ cont) cont)))))
(define current-continuation/λ
(τ (continuation-capture (compose Φ continuation->λ))))
(define-syntax-rule
(letcc/escaper escaper body ...)
((letcc top
(let1 (escaper (λ (proc) (λ args (top (τ (apply proc args))))))
(τ body ...))))))
test/amb/pythagorean: pass
(define (test/amb/pythagorean _)
(⊦= '((3 4 5) (4 3 5))
(amb (λ (ε ? ✗ ✓)
(let ((a (ε (list 1 2 3 4 5 6 7)))
(b (ε (list 1 2 3 4 5 6 7)))
(c (ε (list 1 2 3 4 5 6 7))))
(? (= (* c c) (+ (* a a) (* b b))))
(✓ (list a b c))
(✗))))))
((eta 0.001) (memory #(6291456 2056688 1048576)) (stdout "") (stderr ""))
test/amb/ordered: pass
(define (test/amb/ordered _)
(⊦= '((4 3 5))
(amb (λ (ε ? ✗ ✓)
(let* ((a (ε (list 1 2 3 4 5 6 7)))
(b (ε (list 1 2 3 4 5 6 7)))
(c (ε (list 1 2 3 4 5 6 7))))
(? (= (* c c) (+ (* a a) (* b b))))
(? (< b a))
(✓ (list a b c))
(✗)))))
(⊦= '() (amb (λ (ε ? ✗ ✓) (✗))))
(⊦= '() (amb (λ (ε ? ✗ ✓) (ε '())))))
((eta 0.001) (memory #(6291456 2058648 1048576)) (stdout "") (stderr ""))
test/amb/parameterize: pass
(define (test/amb/parameterize _)
(define q (make-parameter 'outer))
(⊦= '((1 inner outer) (2 inner outer) (3 inner outer))
(amb (λ (ε ? ✗ ✓)
(let* ((inside #f)
(a (parameterize
((q 'inner))
(let1 (a (ε '(1 2 3))) (set! inside (q)) a))))
(✓ (list a inside (q)))
(✗)))))
(⊦= 'outer (q)))
((eta 0.0) (memory #(6291456 2063472 1048576)) (stdout "") (stderr ""))
test/amb/dynamic-wind: pass
(define (test/amb/dynamic-wind _)
(define wlog '())
(⊦= '(1 2 3)
(amb (λ (ε ? ✗ ✓)
(let1 (a (dynamic-wind
(τ (push! 'in wlog))
(τ (ε '(1 2 3)))
(τ (push! 'out wlog))))
(✓ a)
(✗)))))
(⊦= '(in out in out in out in out) (reverse wlog)))
((eta 0.0) (memory #(6291456 2064032 1048576)) (stdout "") (stderr ""))
test/sat-solve: pass
(define (test/sat-solve _)
(⊦= (list (list #t) (list #f)) (sat-solve (x) (or #t x)))
(⊦= '((#t #t) (#t #f)) (sat-solve (x y) (or x y)))
(⊦= (list (list #f #f #t))
(sat-solve (a b c) (and (implies a (not b)) (not a) c)))
(⊦= (list (list #f #t #t #t) (list #f #t #t #t))
(sat-solve
(x1 x3 x4 x5)
(and (or x1 (not x5) x4) (or (not x1) x5 x3 x4)))))
((eta 0.0) (memory #(6291456 2065312 1048576)) (stdout "") (stderr ""))
test/implies: pass
(define (test/implies _)
(⊨ (implies #f #f))
(⊨ (implies #f #t))
(⊭ (implies #t #f))
(⊨ (implies #t #t)))
((eta 0.0) (memory #(6291456 2066576 1048576)) (stdout "") (stderr ""))
(aux continuation): Collatz sequences with letcc
Collatz 3x+1 problem
Direct, continuation-passing and call/cc versions, after Kozen's recitation on CPS.
test/collatz: pass
(define (test/collatz _)
(let ((expected
'(51
154
77
232
116
58
29
88
44
22
11
34
17
52
26
13
40
20
10
5
16
8
4
2
1)))
(⊦= expected (collatz 51))
(⊦= expected (collatz&co 51))
(⊦= expected (collatz&co-abridged 51))
(⊦= expected (collatz&co-abridged2 51))
(⊦= expected (collatz&cc 51))
(⊦= expected (collatz&cc-abridged 51))))
((eta 0.0) (memory #(6291456 1905560 1048576)) (stdout "") (stderr ""))
Categories: scheme
See also
The (aux anthropic) module
The Anthropic Messages API, offline
The (aux cml) module
Events, threads, synchronous variables, the library and I/O
The (aux hakaru10) modules
Random sources, distributions, the language, exact inference and examples
The (aux kanren) modules
Arithmetic, dates, presentation of answers and a union-find miniKanren
The (aux games dice-of-doom) module
Dice of Doom
The (aux machine) modules
Environments, the SC machine and the SECD machine
The (aux schemer seasoned) module
The Seasoned Schemer
The (aux category) modules
Monads: list, maybe, probability, ziplist, difference lists and state
The (aux timsort) module
Sorting and the trace buffer
The (aux fds) modules
Functional queues and union-find
The (aux sxml) module
Rendering SXML to HTML
The (aux variable) module
Logic variables introduced by fresh
The (aux tabling) module
Memoization and tabled definitions
The (aux commons) module
Learning tests for CHICKEN Scheme
Promises
delay and make-promise
The Ackermann function
On unary numbers, as lists
Concurrent ML for CHICKEN Scheme
Porting SML/NJ CML as the (aux cml) library
CHICKEN Scheme
Versions and implementation notes
The SBRAL data structure
Skew Binary Random-Access Lists
Pattern matching
Scheme macrology: a generalized pattern matcher
The (aux hansei) modules
Inference, random sources, lazy lists, logic programming and example models
The (aux nondeterministic) module
Learning tests for Scheme
The (aux stream) modules
Streams, streams after SICP, and sequences and power series
The (aux unittest) module
Bootstrapping a unittest framework
Scheme lang: Chez, 48 and Chicken
Some docs, refs and containers, respectively.
The Reasoned Schemer
miniKanren, microKanren and some implementations
Aggregation predicates for µkanren
Groups, window functions, sets and enumerations
miniKanren, live and untagged
Quine generation via relational interpreters
Pure, declarative, and constructive arithmetic relations
A declarative pearl
Final shift for call/cc
Direct implementation of shift and reset
Call with Current Continuation Patterns
Cogen in six lines
The Seasoned Schemer
The Little Schemer
Adding generic functions to Scheme
Handling control