Search code examples
schemesicpcontinuation-passingtrampolines

How to write analyzer/evaluator functions like `eval-if` in CPS form?


I'm trying to write a toy python Scheme interpreter based on the meta-circular evaluator in SICP. Since python only supports a call stack of limited depth, I have to eliminate the tail calls. I read about trampolines and implemented the parser with it.

But I don't know how to write the analyzer/evaluator functions in continuation-passing style to use them with trampolines. For example, the eval-if function:

(define (eval-if expr env)
    (if (is-true? (eval (if-predicate expr) env))
        (eval (if-consequent expr) env)
        (eval (if-alternate expr) env)))

in python:

def eval_if(expr, env):
    if is_true(eval(if_predicate(expr), env)):
        return eval(if_consequent(expr), env)
    else:
        return eval(if_alternate(expr), env)

when I want to check if the predicate is true, I have to call a new round of eval on it. How should I write this kind of recursive calls in CPS form?


Solution

  • In scheme/Racket, you'd write the CPSed form of this function as:

    ;; evaluate an 'if':
    (define (eval-if expr env k)
      (eval (if-predicate expr) env
            (lambda (testval)
              (if (is-true? testval)
                  (eval (if-consequent expr) env k)
                  (eval (if-alternate expr) env k)))))
    

    Note that this assumes that your 'eval' is also written in CPS. In Python, you can presumably use "lambda" if Guido allows you to; otherwise, I believe that you can define an internal function for this.