Wanted: Better name
While following the course "Declarative Languages" at KULeuven I got inspired to make a Prolog implementation in Python, while relying on Python's parser. This is the result:
from logicpy import *
u, n = Universe().and_namespace()
n.parent[_.alice, _.bob] = True
n.parent[_.alice, _.charlie] = True
n.sibling[_.A, _.B] = n.parent(_.X, _.A) & n.parent(_.X, _.B) & (_.A != _.B)
u.simple_query(n.sibling(_.X, _.Y))
# returns [{'X': Atom('bob'), 'Y': Atom('charlie')},
# {'X': Atom('charlie'), 'Y': Atom('bob')}]
There is also a kind of shell, which has some tricks so you can write your
queries more naturally. Use it through u.interactive()
:
? parent(alice, Child)
{Child = bob};
{Child = charlie};
?
More examples can be found in the tests (logicpy/tests.py
). There you will find more features:
- Evaluation of expressions (mainly math): I pulled a C++ for this and used the bitshift operators:
_.X << _.A * 2
will unifyX
with double ofA
, as long asA
is instantiated. - Cuts: Just use
cut
- Comparisons: As you would expect.
It has, obviously, perfect integration with Python. There are three main ways to integrate your functionality, which are best described using their return value.
Use the @runnable
decorator. Arguments given to your function will be evaluated. Used as a predicate, it will always succeed. Example:
@runnable
def add_article(title, text):
requests.post(".../article/add", {'title': title, 'text': text})
# Can be used as:
n.generate_intro[_.Name] = add_article("Intro " + _.Name, "Hello, I am " + _.Name + ", happy to be here.")
Use the @provable
decorator. This works almost exactly like @runnable
, but depending on the truthiness of the return value it will succeed or fail.
Use the @evaluated
decorator. Again, the arguments itself are evaluated. Example:
@evaluated
def max_(x, y):
return max(x, y)
# Can be used as:
Y << max_(X+5, 8)
Apart from those techniques, you can also subclass from MonoArg
or MultiArg
(or Structure
if you really want), and implement the prove(result, debugger)
method. Yield all results that you find ok. This gives you the most control, but requires more knowledge about the inner workings of this library.
I didn't add any metaprogramming, since this would logically be Python's job. There is no 'standard library'. There are still going to be a lot of bugs. This project contains more lines of Python than the total amount of lines of Prolog I have written in my life, so some things might behave unexpectedly (but I wouldn't know currently). It's more of a proof-of-concept.
However, the biggest disadvantage might be performance. It's pretty slow.
- Lots of generators for a Prolog-like runtime (works pretty well, see the backtracking implementation in
logicpy/builtin.py
!) - Some little hacky tricks to provide the interface (these are somewhat more brittle)
This project is licensed under the MIT License.