Prolog in Prolog revisited

I wrote a small “Prolog in Prolog” interpreter based on clause/2 to fix a strange bug in my CGI in prolog. After fixing the trouble I wanted to extend a little bit the interpreter to cover the “deep cut (!)” for future use.

As once I saw an elegant and small such “prolog in prolog” in middle 1980’s, following my vague memory, I have managed to reproduce it, I hope. As far as the running the following typical sample queries, it seems to work correctly.

?- solve(true).
?- solve(false).
?- solve(false -> true). % Prolog behaviour.
?- solve(1=2 -> 1=2; 2=2).
?- solve(((X=1, X=2) -> (Y = 1; Y=2)); Y =3; Y=4).
?- solve(((X=1; X=2) -> (Y = 1; Y=2)); Y =3; Y=4).
?- solve(solve(((X=1, X=2) -> (Y = 1; Y=2)); Y =3; Y=4)). % idempotency.
?- solve(solve(((X=1; X=2) -> (Y = 1; Y=2)); Y =3; Y=4)).
?- solve(solve((member(X, [1,2,3]), !,
member(Y, [a,b,c]), !,
member(Z, [u,v,w])))).

The following were useful for the interpreter going down only to user-defined predicates:

predicate_property(_, built_in)
predicate_property(_, imported_from(_))
predicate_property(_, interpreted)

Also, now I “qcompile” every my codes, but the builtin clause/2 works as if it traces on source codes in text. Very impressive !

After the success, I tried to improve further the interpreter to avoid using the “deep cut” (in solve/1), because the code itself I saw might have not used “deep cut.”

After several “try and error”, although I could not find a way for “pure prolog” codes, now I have another solve/1 which behaves equally to the first one.

The both codes have almost the same structure, but the second one uses nb_setarg/3 term arguments in stead to keep track the cut (!) occurrences to cut alternatves. The nb_setarg is not “pure”, but the effect was drastic and the impureness was very local, I hope. This is the reason why I uploaded also the nb_setarg version. Of course, it is not my intention to recommend to use impure primitives.

I have uploaded both codes in my pack library(pac) pac-v1.5.1.

library(pac)/misc/prolog-in-prolog.pl  % deep cut version.

library(pac)/misc/prolog-in-prolog2.pl  % nb_setarg version.

$ swipl
?- use_module(pac).

?- [misc(‘prolog-in-prolog’)]. % “deep cut” version.
?- module(prog_in_prog).
(queries above)

[
?- [misc(‘prolog-in-prolog2’)]. % nb_setarg version.
?- module(prog_in_prog2).
(the same queries above)
]

Kuniaki Mukai

1 Like

See also ‘$meta_call’/1 in SWI-Prolog itself (https://github.com/SWI-Prolog/swipl-devel/blob/4d692f51bc9ac95b76364c93597b399820b27d8e/boot/init.pl#L302) for handling cuts.

I am trying to add a tag for this topic since it is in the Category Resources. I am thinking package.

You note

but I can not find this code to help me clarify what tag this needs.

Care to share a link to the uploaded code.

Thanks Jan,

I have skimmed the codes for ‘$meta_call’. It uses not only “deep cut” ! and also the powerful

meta_predicates setup_call_cleanup and the like.

I tried following queries:

?- help(’$meta_call’).

?- trace, ‘$meta_call’(append(X,Y, [a,b])).

?- spy(’$meta_call’), ‘$meta_call’(append(X,Y, [a,b])).

?- ‘$meta_call’(’$meta_call’(append(X,Y, [a,b]))). % works !

But they did not work except the last query. How to put trace points or spy points onto the ‘$meta_call’ ?

No help seems available for ‘$meta_call’.

It was already useful for me to join reset/shift with the simplest prolog-in-prolog of mine to find bugs in my “cgi in prolog.”

It is not clear for me how to use ‘$meta_call’ for such debugging issues. What is the purpose of ‘$meta_call’/1 ?

What is the merit for the user to use ‘$meta_call/1’ ? To the user ‘$meta_call’ seems just the same as the call/1.

Is any document available for '$meta_call’.

Kuniaki Mukai

p.s.

I have returned after more than one year completely off from programming things,

except running my shell script for updating git version SWI-prolog. I am having hard time

to catch up with SWI-Prolog progress.

1 Like

The comment above the implementation more or less explains what it does. As it starts with a $, it is internal and not for normal users (it can change, disappear, etc. without notice). It implements call/1, handling control structures and cuts. Normally call/1 is handled by the VM, but the way this is done is not compatible with reset/shift and therefore we need a pure Prolog implementation for call/1.

If you want to play around with it, I’d copy the definition into a normal file and rename the predicate.

The old stuff should still work :slight_smile:

If “prolog in prolog” tag is available, please use it. My post on prolog-in-prolog issue is not directly
related to the pack PAC release. I should be careful on tagging.

Kuniaki Mukai

1 Like

I see $meta_call/1 = call/1. Thanks.

Now I realize that both of two prolog-in-prologs of mine are deeply indebted

to your $meta_call/1 through via call/1.

It is not clear for me the relationship between reset/shift of SWI and

the need prolog-in-prolog in more pure prolog. It seems interesting

but also it looks too hard for me to make some contribution.

Kuniaki

It is a nasty detail. The continuation created by shift/1 contains references to the involved clauses. call/1 creates a volatile clause on the stack if the argument is a control structure. A reference to a volatile clause is not a good idea as the stack unwinding of the reset/shift already discards this clause.