I follow the Hassan’s reconstruction manual (now at page 24 of 129) and it seems short and nice but hard in some way.
I’m an experienced Java software engineer
I follow the Hassan’s reconstruction manual (now at page 24 of 129) and it seems short and nice but hard in some way.
I’m an experienced Java software engineer
I take you are referring to
“Warren’s abstract machine : a tutorial reconstruction” by Hassan Aït-Kaci (WorldCat)
How many days will it realistically take to code up a working prototype of WAM (without optimization)?
As for the timeline, it depends heavily on your experience. For someone already comfortable with Prolog internals and abstract machines, it might take a few weeks. For others, it could take significantly longer, or remain incomplete.
Even assuming you do get a prototype working, the more difficult question is how you would establish its correctness?
Once you get to the level of the ISO core standard, it should be easy enough to get Logtalk running and use its pretty extensive test suite. The real question IMO is “why would you”? There are plenty of Prolog engines out there and while getting the basics to work is pretty easy, getting it to scale, properly optimized, provide a debugger, foreign language interface, supporting more modern features such as constraints or tabling is pretty involved. Why not take an existing Prolog system and if it does not exactly what you want, collaborate with the developers to improve it? It saves you a lot of time and works towards fewer sustainable implementations rather than more unsustainable ones.
Writing a WAM is probably easier than writing a decent compiler from Prolog to WAM (I did both for a master’s thesis a long time ago). Also, there are quite a few built-in predicates that need to be implemented.
You might want to look at Peter Van Roy’s thesis on the Aquarius compiler.
(If you want to deal with just pure Prolog, it’s somewhat easier; “cut” can be tricky to get right, for example)
See also: https://www.ps.uni-saarland.de/Publications/documents/VanRoy_SequentialPro.pdf
Is this what you are referring, or was it close and you had something else in mind?
Knowing about the extensive test suite, this might be a good test for a Long-Horizon project for an LLM.
For any one thinking about doing this, it is not uncommon for these sorts of projects to run for a few days and cost several thousand dollars in tokens. However if you write a well defined prompt with the right details, you might get it done with just a few hundred dollars of tokens.
Years ago I started keeping track of task that LLMs just failed at and year after year they would fail at being able to create useful SWI-Prolog code, starting with Claude Sonnet 4.5 that changed. Now both OpenAI and Anthropic models can create SWI-Prolog more or less.
So the next tasks for LLMs that I am starting to track are Long-Horizon tasks, this looks to be a good candidate.
One reason I mentioned earlier is using it as a test case for a long-horizon task.
Another practical motivation is that many programmers currently aim to migrate systems to Rust, or to rebuild them from the ground up using it.
From a different angle, I would be interested in exploring whether a WAM—or another Prolog engine—could be implemented in Lean 4 alongside formal proofs. I do not yet know what the full set of required proofs would look like, but the exercise itself would likely be a valuable learning experience.
Thank you very much
My main goal is educational purpose: to have 100% understanding of Prolog engine. It is only possible if I code it up from scratch. I’ve already implemented a working interpreter using ISO standard part I model (stack-based) as a reference, but from time to time I feel like this part of the standard (7.7 Executing a Prolog goal) has some deep flaws and their model isn’t very codable, but I can be wrong.
I thought that WAM can bring me deeper conceptual understanding, but now I’m not sure. Maybe it is better to continue with ISO model and think about it deeper.
Can you recommend me a Prolog execution model or engine which is the best one for understanding/educational purposes/pedagogical clearness and neatness? No need to be the fastest one
Well, this paper started SWI-Prolog. It is really easy to implement and describes Prolog compiled into 7 instructions. Currently SWI-Prolog has over 200 instructions in its VM ![]()
Is your goal to learn the virtual machine instructions that power a Prolog implementation or to understand Prolog?
When I learned Java I also took a similar route to understand the JVM and while it was nice to know the only practical piece of information I learned from months of work was that the JVM did not implement tail recursion, they may have done it since.
The other thing about learning Prolog is that there is text book Prolog code and real world Prolog code. The only book that actually helped with real world Prolog coding was The Craft of Prolog by Richard A O`Keefe (WorldCat)
Also see:
You might find the history section of value.
It is possible to code directly in opcodes of JVM (Jasmin project) and also decompile your class files with javap command. I coded in pure JVM opcodes here and I feel it was useful. I also enjoyed x86 assembler programming when I was a kid. As a result, I decided to try WAM to code directly in opcodes but it doesn’t seem to be so helpful or maybe I just lack of understanding and need to invest more time
Unfortunately the history does not go back that far. If I recall correctly though, I started with the original 7 instructions (as long as you initialize the variables there is no need for distinct head and body instructions) and compiling the Prolog compiler using Edinburgh C-Prolog. Next I wrote a simple read/1 and write/1 in C, so I could actually run Prolog
The rest is history ![]()
Good to hear.
Please do not take my earlier replies as discouragement. They are intended more as cautionary notes—this is a path many start but relatively few complete. That said, it is also one of those efforts where the value often lies more in what you learn along the way than in the final result.
One additional point worth noting: many of the people responding in this thread have decades of experience. It would not be surprising if the combined experience represented here exceeds a century. There is a substantial amount of hard-earned perspective behind the feedback.
Since you have already explored assembly, JVM opcodes, and other low-level or virtual machine models, you may also find the following resources relevant:
The title and description of the second resource do not fully convey its practical value. It provides a solid, ground-up understanding of how Lambda Calculus is applied in real systems. If you are interested, this older discussion gives additional context:
One additional option for tackling the more difficult parts is to use an LLM-based coding tool, such as OpenAI Codex or Claude Code.
In my experience, there have been projects where I was blocked for years; with the assistance of these tools, I was able to overcome a key hurdle and continue making progress.
I think that implementing a compiler to WAM (or similar, such as the 7 instruction machine) is more useful than implementing WAM – you’ll learn about the WAM by doing this and also learn about the issues involved with compiling Prolog. I don’t know if there’s an existing WAM implementation that you could use as a target (I don’t have the Hassan Aït-Kaci’s paper handy - I vaguely recall that it has at least pseudo code for the WAM instructions).
The first version of SWI-Prolog implemented it as a foreign predicate that manipulated the choice points. That is not so hard.
That is a key feature that is still maintained in SWI-Prolog. assert/1 is pretty much the standard compiler with some options disabled. clause/2 does decompilation. Dynamic predicates are not significantly different from static predicates and clause/2 works both on dynamic and static code. As static code is not so different from dynamic code, we can easily implement hot swap, i.e., recompile code while the code is running in another thread. The ZIP also easily implements a debugger without specializing the code or interpreting it.
The downside is that some operations remain a bit slower. Notably tail calls, although recent versions reduced the gap significantly by introducing two sets of instructions for the last call, one that creates a new frame and one that manipulates the running frame for running the tail call.
Depart is indeed in there, but not how to implement it (if I recall correctly). As we have a sequence of instructions that build the arguments for the new call followed by a depart we do not know there is a depart rather than a call. So, old SWI-Prolog created a new frame. Then found the depart and determinism and overwrites the old frame with the new frame and continues. That is problematic though. In the old days, the environment stacks had internal reference pointers and you could thus not simply copy the frame. Bart Demoen talked me into never having reference pointers in the environments. This means that if we need such a pointer we create a variable on the global stack and make the reference from there. That is a bit of overhead, but stack frame manipulation gets a lot simpler, so it pays off.
But still, we create all arguments on the new frame and then copy them. That is where the two branches come in: if we can do a tail call we modify the current frame. The current instruction set for that is quite limited. If there is no way, we still go the old route, but that is infrequent now. The itcall is not a loop call. It could be if there is only one clause, but otherwise we need to restart the clause search (could be improved). Self calls are common and often time critical though and we safe an argument as well as some checks.
There are many reasons why we would consider constructing from scratch a WAM. The most obvious is to have a detailed and practical understanding of the Prolog compiler. Another reason is to keep using Prolog while not being restricted to its existing syntax. Inbuilt syntactic flexibility would keep most of us happy. By syntactic flexibility I mean the ability to reorder and rename terms and operators in a manner equivalent to the “cannonical” way.
A typical example would be the ability for the programmer to code in a way closer to his/her natural language syntax:
equals(X, Y):- … becomes
… (X, Y)ቢያክል
where the variables precede the predicate name, and the conditional :- is replaced by ቢ, it’s equivalent in a given natural language.
The absence of such syntactic flexibility is most probably the main reason why we seek a “better” programming language. Most of us are happy with Prolog while we would want to see similar improvements. But the ISO standards are unlikely to yield to such drastic requests. Would development teams consider it feasible within the existing framework? Not sure.