The Metacircular Evaluator

The metacircular evaluator is what we've been working towards for much of this class. It's a grown-up version of Scheme-1 that supports define and set!. It's also an implementation of the Environment Model of Evaluation, which means it follows all the rules for lambda-created procedures and procedure calls that regular Scheme does.

What does "metacircular" mean? Well, it's "circular" because it's an implementation of Scheme using Scheme. But it's "meta" because we're building a new Scheme on top of STk. Ergo, "metacircular". (That, or Abelson and Sussman just thought it sounded cool.)

(What's an "evaluator"? Pretty much the same as an "interpreter" — it's a program that takes in expressions and evaluates them. The ultimate in DDP: a Scheme interpreter doesn't do anything on its own, but can be programmed to do everything.)

An interesting thing about implementing an evaluator is that your new language can have features that your implementation language might not. For example, we saw in lab that you can force arguments to be evaluated right-to-left in MCE-Scheme, even though Scheme doesn't guarantee an order and STk actually uses left-to-right. A more subtle point is that the metacircular evaluator doesn't use any higher-order procedures.

No, really. Go check if you don't believe me.

MCE-Scheme supports higher-order procedures just fine, of course. This proves you can implement higher-order procedures even in a language that doesn't have them, like C.

For those who know C, this is not exactly true anymore! Both C++0x "lambdas" and Apple's "blocks" are implementations of lambda / closures / higher-order procedures in C, and they're already supported in some of the most popular compilers.

Okay, enough talk. The most important procedures in the Metacircular Evaluator are, as you'd expect, mc-eval and mc-apply.

mc-eval

(define (mc-eval exp env)
  (cond ((self-evaluating? exp) exp)
        ((variable? exp) (lookup-variable-value exp env))
        ((quoted? exp) (text-of-quotation exp))
        ((assignment? exp) (eval-assignment exp env))
        ((definition? exp) (eval-definition exp env))
        ((if? exp) (eval-if exp env))
        ((lambda? exp)
         (make-procedure (lambda-parameters exp)
                         (lambda-body exp)
                         env))
        ((begin? exp) 
         (eval-sequence (begin-actions exp) env))
        ((cond? exp) (mc-eval (cond->if exp) env))
        ((application? exp)
         (mc-apply (mc-eval (operator exp) env)
                   (list-of-values (operands exp) env)))
        (else
         (error "Unknown expression type -- EVAL" exp))))

Environments and Procedures in the MCE

How should we represent these very important concepts? Well, we can answer that by thinking about what each thing represents.

But these are ADTs as well. The code for the Metacircular Evaluator has a lot of selectors for each of these, and you can mostly just say what you mean (procedure-body, extend-environment, etc.) when you work with these.

mc-apply

(define (mc-apply procedure arguments)
  (cond ((primitive-procedure? procedure)
         (apply-primitive-procedure procedure arguments))
        ((compound-procedure? procedure)
         (eval-sequence
           (procedure-body procedure)
           (extend-environment
             (procedure-parameters procedure)
             arguments
             (procedure-environment procedure))))
        (else
         (error
          "Unknown procedure type -- APPLY" procedure))))

Back to Jordy's home page | Course home page