This states that: First, the empty conjunction (of goals) is true, and second, if there is at least one goal left, than the conjunction is true if there is a suitable clause whose body evaluates to true, and the same holds for all remaining goals.
For example, we can define append/3 as follows in this representation:
And now we can use our meta-interpreter to evaluate its own code as it interprets a program, arbitrarily deeply layered:
?- mi([mi([mi([append([a,b,c],[d,e],Ls)])])]).
Ls = [a, b, c, d, e].
Hence, Prolog admits a meta-circular evaluator in at most 5 lines of code. With a better representation for clauses (using list differences), you can reduce the interpreter to 4 lines of code and at the same time make it tail-recursive.
https://news.ycombinator.com/item?id=17020655 : A question I had asked about interfacing Excel, which provoked some useful responses. I now use this as my authoritative list of ways to extend Excel's functionality.
https://news.ycombinator.com/item?id=18314265 : Fascinating comment about, well, all kinds of stuff, but mainly PostScript. (DonHopkins. Another user whose comment history is a seam of gold.)
That's a very interesting topic and nice write-up, thank you for sharing!
For comparison, here is a small interpreter for a subset of Prolog, written in Prolog:
This states that: First, the empty conjunction (of goals) is true, and second, if there is at least one goal left, than the conjunction is true if there is a suitable clause whose body evaluates to true, and the same holds for all remaining goals.
For example, we can define append/3 as follows in this representation:
and then evaluate it with our interpreter:
Characteristically, it also works in other directions. For example:
and also:
Now the point: The clauses of the meta-interpreter itself can also be stated in this form, namely as:
Now we only have to define what clause_/2 means, which we can do with:
And now we can use our meta-interpreter to evaluate its own code as it interprets a program, arbitrarily deeply layered:
Hence, Prolog admits a meta-circular evaluator in at most 5 lines of code. With a better representation for clauses (using list differences), you can reduce the interpreter to 4 lines of code and at the same time make it tail-recursive.