Theoretically, one could write an interpreter specifically for the purpose of nesting other interpreters, which would then (nearly) remove itself from memory as it transfers control to the second interpreter, but I know I'm not quite insane enough to start working on such a thing.
If you're interested in something similar but a little more theoretical, take a look at "Simply Easy"[1], a little paper on implementing a couple of variations on the lambda calculus. The main idea is to demonstrate how to evaluate a dependently typed language.
It starts by looking at how to evaluate the simply typed lambda calculus and then going from that to a dependently typed lambda calculus. Surprisingly, the transformation is not all that complicated!
Well, the semantics of a lazy language are a bit different than usual. While I agree that pages of s-expressions are hard to feel, seeing the graph reduction algorithm on a few examples was quite refreshing.
13 comments
[ 25.4 ms ] story [ 916 ms ] threadA compiler, if asked to "execute" itself a million times will generate code that is still reasonably fast.
An interpreter, if asked to "execute" itself a million times, will generate code that is a million times slower.
It starts by looking at how to evaluate the simply typed lambda calculus and then going from that to a dependently typed lambda calculus. Surprisingly, the transformation is not all that complicated!
The actual code is in Haskell.
[1]: http://strictlypositive.org/Easy.pdf
I think I'll save myself the wasted time and just use X from the get-go.
https://bitbucket.org/quiark/hsc
The whole purpose of that mental gymnastics was to learn x86 assembly while practicing my Haskell ;)