Friday, December 22, 2006

A self-evaluating evaluator

December is always a busy month, so the number of blog posts have been low for a while. To make up for it, I have been digging in the archives and found a self-evaluating evaluator. Erann Gat back in 2002 asked the following question in comp.lang.scheme:

The topic of self-generating programs (a program whose output is itself) comes up periodically here, but I've never seen the topic of a self-evaluating program discussed. Of course, meta-circular interpreters are ubiquitous, but the usual metacircular interpreter you find in textbooks typically evaluates a slightly different dialect than it is actually written in.

My question is: what is the shortest meta-circular interpreter that is actually capable of evaluating itself?

It was quite fun to write a short meta-circular interpreter. The shortness-constraint creates a tension between powerful constructs and easily-implementable constructs, when choosing language features to include in the language. My solution below has the following features:

conditional construct

functions (of one argument)

application

quotation

This set of features is pretty minimal. The requirement that the evaluator must be self-evaluating means, it must be possible to pass the code of the evaluator to the evaluator, so quotation is just the right tool. Note that variable assignment (set!) is missing.

Since only functions of one argument is supported, it is necessary to curry the normal Scheme functions in the initial environment given to the evaluator. This can be seen in the following version of factorial:

The standard definition of factorial is recursive. The chosen languages supports neither recursive bindings nor assignment, so instead we use the same trick, the Y-combinator uses. To calculate factorial of 5, one must write: ((fact fact) 5).

Since the evaluator must be self-evaluating, the definition of the evaluator uses the same trick as the factorial example. To call the evaluator on the factorial program, one writes:

You'll notice I don't have a fourth time. Something was taking exponential time to complete, and I got worried that it was going to crash DrScheme before it reached and answer, so I stopped the test.

In the name of good sport, I'm going to post my core-form evaluator that is the result of an exercise in TSPL. I'll see if I can get it to run four levels deep and report the times. Mind you it's not my code, just my transformation to core form, so regardless, Dybvig will still take all the credit (or blame.)