Question

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?

Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top