8 Refactoring to CPS
If we’ve been through the previous part, we can keep using the same file. Or we can use 4-functions.rkt as our starting point.
8.1 Some stuff will have a continue-parameter
We will rewrite a few functions so they have a continue-parameter, and so that, instead of returning a result, they apply continue to a result. We will put continue just after env in the parameter lists. E.g. eval-application will go like (eval-application env continue fun args).
8.1.1 (eval-exp env continue exp)
eval-exp isn’t too bad. In most of the match-clauses we return a value pretty directly. In those cases we will pass the values along to continue instead. In the case where we call eval-application, we will pass our continue along to eval-application and put it in after env parameter. The same goes for eval-sequence.
8.1.2 (eval-sequence env continue exps)
The cases where we have some rest-expressions are a little trickier. In, say, the 'define-case, we must make a continuation-function to use with eval-exp. Like:
(eval-exp env (λ (value) your code here) exp)
Within this continuation-function, we will do the stuff we previously did after the call to eval-exp: Extend the environment and call eval-sequence again. We will pass our “original” continue to eval-sequence.
8.1.3 (eval-application env continue fun args)
(define (eval-arguments env continue args) (match args ['() your code here] [(list arg rest ...) your code here]))
8.1.4 Our “primitives”
Instead of e.g. the +-function we want a function that has a continue-argument first:
(define (my-plus continue . args) your code here)
When this function is applied, all the arguments after the continue are collected in args, as a list. We can use the apply-function to apply the original +-function to the args. (And we want to apply continue to the result rather than just returning it.)
(define (primitive function) (λ (continue . args) your code here))
could be convenient.
8.1.5 (make-function env parameters body)
We’re not adding a continue-parameter to make-function function, but we need to add it to the function returned by make-function. That continue should be passed in as the second argument to eval-sequence.
8.1.6 (evaluate input)
For now, we want evaluate to work the same way as before, so we are not adding a continue-parameter to it. But it does use eval-exp so we need to add a continue-argument there. We will use Racket’s identity-function.
8.2 So that did nothing
So, if we got things right then we have kind of made no changes. Under the hood things work differently, but there are no new features and all the expressions in the language we’re making should evaluate to the same values.
How dull? On the plus side we didn’t have to write any new tests...