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?
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.