The (aux continuation) modules

Classic operators, escapers, amb and Collatz sequences

(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 ""))