PyPy
PyPy[prolog-interpreter]

Pyrolog: PyPy's Prolog interpreter

Pyrolog, PyPy's Prolog interpreter was written by Carl Friedrich Bolz as part of his bachelor thesis. It aims at fully implementing the Prolog ISO specification. Currently it implements the core Prolog semantics and many, but not all, ISO builtins (it is especially lacking when it comes to I/O and module support). Its speed is still quite a bit below that of highly optimized Prologs, roughly 10-100 times slower than Sicstus Prolog. In addition, it currently is not very polished in many respects.

This page probably won't make too much sense to you if you don't know some Prolog. Learn Prolog Now! is a rather nice book (available online) to learn some Prolog with (but it's probably not a good idea to use Pyrolog while learning since it is too rough for that).

For a more detailed description of the implementation of the Prolog interpreter see the A flexible Prolog interpreter in Python draft paper.

Example useage

First some simple examples that show simple unification:

pypy/bin$ ./pyrolog.py
PyPy Prolog Console
>?- X = f(Y, a, b), Y = [1, 2, 3].
yes
X = f([1, 2, 3], a, b)
Y = [1, 2, ...]


yes
>?- X = f(Y, a, b), Y = [1, 2].
yes
X = f([1, 2], a, b)
Y = [1, 2]


yes
>?- f(A, B, c) = f(a, b(1, 2), C).
yes
A = a
B = b(1, 2)
C = c

A more complicated example with an actual function: First define the function using assertz:

pypy/bin$ ./pyrolog.py
PyPy Prolog Console
>?- assertz(takeout(A, [A|B], B)).
yes
A = _G0
B = _G1


yes
>?-
>?- assertz(takeout(A, [B|C], [B|D]) :- takeout(A, C, D)).
yes
A = _G0
B = _G1
C = _G2
D = _G3


yes

Then use it:

>?- takeout(3, [1, 2, 3, 4], R).
yes
R = [1, 2, 4]


yes
>?- takeout(X, [a, b, c], Rest).
yes
Rest = [b, c]
X = a
;
yes
Rest = [a, c]
X = b
;
yes
Rest = [a, b]
X = c
;
no
>?- takeout(3, X, [a, b]).
yes
X = [3, a, b]
;
yes
X = [a, 3, b]
;
yes
X = [a, b, 3]
;
no

And of course the typical "family tree" example can't be left out (who can find the most boring names), this time using an actual file instead of asserting everything.):

pypy/bin$ cat > family.pl
parent(john, mary).
parent(anne, mary).
parent(john, paul).
parent(anne, paul).
parent(john, jack).
parent(anne, jack).
parent(jack, sophie).

descendant(X, Y) :- parent(X, Y).
descendant(X, Y) :- parent(X, Z), descendant(Z, Y).

Now we can query this database in the following way:

pypy/bin$ ./pyrolog.py family.pl
PyPy Prolog Console
>?- descendant(john, X).
yes
X = mary
;
yes
X = paul
;
yes
X = jack
;
yes
X = sophie
;
no
>?- findall(X, descendant(anne, X), Result).
yes
Result = [mary, paul, jack, sophie]
X = _G0

Translating the interpreter to C

Just as you can translate PyPy's Python interpreter, you can also translate the Prolog interpreter to C:

pypy$ cd translator/goal
pypy/translator/goal$ python translate.py targetprologstandalone.py

Some implementation notes

The main Prolog data structures including the unification algorithm are defined in pypy/lang/prolog/interpreter/term.py. The Prolog resolution engine in pypy/lang/prolog/interpreter/engine.py. All the builtins are defined in the pypy/lang/prolog/builtin/ directory, the most important ones being in pypy/lang/prolog/builtin/control.py.