Meta interpreter circularity in SWI Prolog

I’m using: SWI-Prolog version 7.6.4

I wrote a Prolog meta interpreter some years ago, taht worked well in GNU Prolog. However, I can’t make gprolog work on Linux anymore, it seems tehre is no support to it. That’s a pity.
Now I am porting it to SWI Prolog and it works well, except for a circularity issue.
When I call the meta-interpreter to execute itself, I get a fail. I traced it and what I got is:

^  Call: (13) predicate_property((\==)/2, built_in) ? creep
^  Fail: (13) predicate_property(user:(\==)/2, built_in) ?

How can I circumvent this, please?

1 Like

The comment by LogicalCapitain in docs for predicate_property/2 explain the behaviour: you should ask for

?- predicate_property(X \== Y,P).
P = visible ;
P = built_in ;
P = foreign ;
1 Like

Thank you for your suggestion! It solved my problem!

I was astonished to see that asking for the property, showed it is not built-in anymore, but interpreted.


1 Like

Glad my hint was useful. Anyway, I’ve tried to install GNU Prolog (from source) on Ubuntu 16.04 without problems. Just, since I didn’t configured (for laziness) the INSTALL_DIR I had to use sudo make install as final step.

In your meta-interpreter, I suggest something like this to avoid unnecessary choicepoints:

predicate_property(Pred,P), memberchk(P, [built_in,foreign])

Also note that (==)/2 has more results (you should read the docs to decide which of these should be added to [built_in,foreign]):

?- forall(predicate_property(_\==_, P), format('~q~n', [P])).

Are you certain?

On my computer (with Linux on it):

$ gprolog
GNU Prolog 1.4.5 (64 bits)
Compiled Jul  7 2020, 21:25:21 with gcc
By Daniel Diaz
Copyright (C) 1999-2020 Daniel Diaz
| ?-

There are roughly 5 classes of predicates relevant to meta-interpretation:

  • With predicate property foreign. These are written in C (or have a C wrapper to Java/Python/…). You cannot do clause/2 and thus you cannot meta-interpret them.

  • Stuff handled by the compiler that has a clause that is exactly the same. Below is an example. You can get a clause, but this is the same as the original clause and thus you make no progress :frowning: You find the full set in boot/, currently from line 318.

    (G1, G2) :- call((G1, G2)).
  • Normal Prolog code that is part of the core system. They are reported as built_in.

  • Normal Prolog code from the libraries. The way to find them, as @EricGT mentioned is using the imported_from(Module) property and module_property/2, checking for class(library)

  • User code. This may be local to the module (or not in a module) or imported user code.

The first two cannot be meta-interpreted. The rest is a choice up to the user.


This gets really tricky. I think the only way to call ,/2 is using call/2 (or call/3), as in

?- call(','((between(1,3,X),!)),writeln(X)).
X = 1.

I think this is correct as the above must be the same as call((between(1,3,X),!,writeln(X))). I think all other ways to call ,/2 are handled by the compiler rather than the predicate.