Any program that consumes some amount of stack, when converted to CPS and run, suddenly consumes no stack space at all. Why? Does this make CPS a good general technique for reducing the space consumption of programs?
CPS the following Scheme function. You don’t need to CPS
primitives such as empty?, first,
rest, cons, cons? and
<. Assume that the function argument to
filter is in CPS. Feel free to do this manually (as we did for web
programs), rather than using the lambda-heavy transformation covered
in chapter 18 (the convert method covered at the end of class).
;; filter: (x -> bool) (listof x) -> (listof x)
(define (filter f l)
(cond
[(empty? l) empty]
[else (cond
[(f (first l)) (cons (first l)
(filter f (rest l)))]
[else (filter f (rest l))])]))
Now change the following expressions to use
the CPSed version of filter.
(define (less-than-three x)
(< x 3))
(filter less-than-three
(cons 1 (cons 4 empty))) ;; this evaluates to (list 1)
The Java security model uses a primitive called stack inspection. Let us implement a simple version of this. Assume the language had two new primitives:
<E> ::= ...
| {bless <E>}
| {check}
The bless primitive creates a blessed stack frame for
the duration of evaluating its sub-expression. The check
primitive traverses the run-time stack; if it finds a blessed frame it
evaluates to 0 (so you can, for instance, use it inside
sums without affecting the outcome), otherwise it terminates the
program's execution.
Extend the cps interpreter presented in the text (fig
20.2) with these two new language constructs.
Note: Java lacks tail-call optimization ostensibly because this hurts the ability to implement stack inspection. In fact, this claim is entirely false. But we're stuck with the result of this decision, making the JVM a poor target for other language compilers. Unfortunately, .NET has also adopted this mistake, as the paper explains.
Submit a plain text file with your answer to problem 1 and separate code files for problems 2 and 3.