- 169comments
- 213comments
- 26comments
- 237comments
- 38comments
- 1comments
- 63comments
- 259comments
- 12comments
- 49comments
- 74comments
- 49comments
- 240comments
- 87comments
- 12comments
- 51comments
- 17comments
- 177comments
- 15comments
- 163comments
- 89comments
- 3comments
- 29comments
- 180comments
- 16comments
- —discuss
- 151comments
- 291comments
- 18comments
- —discuss
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.
Nice- but why only half a meta-interpreter? A complete Prolog meta-interpreter should still be able to interpret iself, no?
Yes, a complete Prolog meta-interpreter would definitely be meta-circular.
However, it is quite hard to write an interpreter for complete Prolog, both in Prolog and also in other languages. Take for example handling of !/0. It is not easy to add handling of !/0 to the meta-interpreter I showed, especially if you want to retain meta-circularity. You cannot simply use a !/0 on the meta-level, because that does not get cut transparency right. One way to express !/0 on the meta-level is to use catch/3 and throw/1. However, if you do this and want to retain meta-circularity, then you must also handle catch/3 and throw/1 correctly, and soon you really will have to handle almost the entire language, which is quite complex to implement even though it has a very simple syntactic structure.
With "cut transparency", I mean that the scope of !/0 depends on its context. For example, we have:
and on the other hand:
Such properties make an interpreter for complete Prolog rather complex, and for this reason I have shown a meta-circular interpreter that can handle only a (Turing-complete) subset of Prolog. Thank you for your interest!
Ah. My apologies. As usual I lack precision. I was thinking of a meta-interpreter for the logically pure subset of Prolog- no cuts, or exceptions.
That should be covered by the classic Prolog meta-interpreter, no? I mean this one:
This would work if clause/2 always failed if there is no matching clause. Indeed, in some systems, that was the case. But now, clause/2 may and will throw an error for example on:
See also the Prolog ISO standard:
In this interpreter, the third clause of prove/2 is also applicable if the others are applicable, because L1 subsumes both true and terms of the form (X,Y). For this reason, we get for example:
whereas we expect this to succeed, because (true,true) does. Hence, to make this interpreter actually work, more must be added, and to make it meta-circular (i.e., able to interpret its own code), these features must then also be handled.
In the representation I used, these issues do not arise because I am using a so-called clean representation. With such a representation, I can tell for certain what the individual goals are, as the individual goals are symbolically distinguished from conjunctions of goals.
I didn't think of the case of a missing clause. Thanks for the explanation :)
The post is based on SICP, and the author briefly discusses dynamic scoping after finding it in some other blog posts or something. In fact, the first edition of SICP contained a discussion of dynamic scoping. I don't know why it was removed from the second edition, because it's an interesting and important topic. Dynamic scoping also features in the SICP videos [1], which were produced around the time the first edition came out.
[1] https://www.youtube.com/watch?v=t5EI5fXX8K0&feature=youtu.be...