|20-CS-4003-001||Organization of Programming Languages||Fall 2017|
;; an infinite recursion (define succ (lambda (n) (cons n (succ (+ n 1))))) ;; (succ 1) -> aborts on stack depth ;; a continuation is grabbed by lambda () (define succ$ (lambda (n) (cons n (lambda () (succ$ (+ n 1)))))) ;; the procedure is the continuation (succ$ 1) ;; (1 . #[procedure]) ;; easy access to the continuation (define rest (cdr (succ$ 1))) ;; #[procedure] ;; invoke the continuation (rest) ;; (2 . #[procedure]) - a new continuation ;; invoke four continuations - returns 5 (car ((cdr ((cdr ((cdr ((cdr (succ$ 1)))))))))) ;; routine to pull out the first ;; n tokens of a stream ;; ex: (take$ (succ$ 1) 10) ;; creates a list (define take$ (lambda (s n) (if (zero? n) '() (cons (car s) (take$ ((cdr s)) (- n 1)))))) ;; routine to return the nth token in a stream ;; (take_nth$ (succ$ 1) 10) -> 10 (define take_nth$ (lambda (s n) (if (= n 1) (car s) (take_nth$ ((cdr s)) (- n 1))))) ;; factorial in non-continuation passing style ;; (fact3 -1) -> out of memory error ;; (fact3 8) -> (40320 5040 720 120 24 6 2 1) (define fact3 (lambda (p) (letrec ((fact (lambda (n acc) (if (> n p) acc (fact (+ n 1) (cons (* n (car acc)) acc)))))) (fact 2 '(1))))) ;; continuation passing style ;; (take$ (fact3$ 1 1) 6) -> (1 2 6 24 120 720) ;; (take_nth$ (fact3$ 1 1) 8) -> 40320 (define fact3$ (lambda (n acc) (cons (* n acc) (lambda () (fact3$ (+ n 1) (* n acc)))))) ;; put it inside a letrec (define fact4$ (lambda (n) (letrec ((fact$ (lambda (n acc) (cons (* n acc) (lambda () (fact$ (+ n 1) (* n acc))))))) (take$ (fact$ 1 1) n))))
continuation: a construct that gives a programming language the
ability to save the execution state at any point and return to that
point at a later time in the program.
Function succ is an infinite recursion aiming to produce a
list of all positive integers if the argument is 1 - it aborts with
stack overflow. Function succ$ does the same thing except
that the recursive call to succ$ is wrapped inside
a lambda. This stops execution of (succ$ 1) with a
cons pair consisting of a first token (1) plus a continuation that
is the thunk (lambda () ...) which is identified by scheme
as a #[procedure]. The continuation can be invoked to
continue execution for one more step like this:
Function take$ invokes the continuations any number of times, assembling a list of first tokens on the way. Function take_nth$ does the same except it returns the last element only. These are utilities that are used below.
Function fact3 computes a list of consecutive factorials in reverse order. It is not written in continuation passing style. The invocation (fact3 -1) results in no output. Function fact3$ does the same but it written in CPS. It can be coupled with take$ or take_nth$. It is used in a letrec in fact4$. The invocation (fact4$ -1) returns a value.