Proper subsumes_term/2 in SWI-Prolog? - prolog

Lets assume SICStus Prolog is the benchmark for the
implementation of certain predicates, even ISO core standard
predicates. Especially in connection with attributed variables.
I then find these examples here. It's from SICStus 4 and not only SICStus 3:
?- when(nonvar(X), X=a), subsumes_term(X, b), X = a.
X = a ?
yes
?- when(nonvar(X), X=a), subsumes_term(X, b), X = b.
no
When doing the same in SWI-Prolog I get different results:
?- when(nonvar(X), X=a), subsumes_term(X, b), X = a.
false.
?- when(nonvar(X), X=a), subsumes_term(X, b), X = b.
false.
How would one implement a workaround in SWI-Prolog? ROKs METUTL.PL probably doesn't help, since it uses normal unification.

Here is a suggestion (not actually tested in SWI-prolog):
subsumes_term_sicstus(X, Y):-
copy_term(X-Y, XC-YC, _),
subsumes_term(XC, YC).
The idea is simply to copy the two structures then use the original predicate on the copies, which do not have attributes or frozen goals attached.
According to the documentation, it appears that copy_term/2 copies the attributes of attributed variables in SWI-prolog (but not in SICStus), so I am using copy_term/3 instead here. I see that there is also a copy_term_nat/2, which might be used instead.

Related

PROLOG, Is it possible to collect all result from a predicate to a list, without using built in predicates, such as bagof or findall

If for example, I have a Prolog predicate like
a(A, B).
Is it possible to collect, given a value of A, is it possible to collect all values of B that succeeds the predicate a, into a list, without using built in predicates such as bagof/3 or findall/3.
You have two obvious options (obvious to me; it seems there is more). One is to indeed use the database to save the state. This has at least one pitfall: depending on the name you decide to use for the temporary state, you might destroy some other state your program is keeping. This is the same old "global state"/"global variable" problem that all languages suffer from.
The other option would be to use a "local variable" and non-backtracking assignment to it to keep the temporary state. This is most probably going to be implementation dependent. For starters, you can look at nb_setarg/3 for SWI-Prolog.
However, both solutions are silly, given that you have findall, bagof, setof. You must motivate the need for something else to replace those. Just saying "is it possible" is not good enough since it is possible, but completely unnecessary, unless you know something else that you aren't telling us.
Here's a sketch of a stupid setof that uses other builtins, though not assert, and not exactly the ones listed by #false in a comment.
We'll use a list accumulator to collect solutions:
stupid_setof(Template, Goal, Set) :-
stupid_setof(Template, Goal, [], Set).
There are two cases to consider: Either the Goal can enumerate a solution we have not seen so far, or the only ones it can enumerate are already in our accumulator.
First, the case where there are no solutions we haven't seen. In this case we're done.
stupid_setof(Template, Goal, SolutionsSeen, Set) :-
\+ ( call(Goal),
\+ member(Template, SolutionsSeen) ),
!,
sort(SolutionsSeen, Set).
Now for the stupid part. Consider:
foo(a).
foo(b).
foo(c).
?- SolutionsSeen = [], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [],
X = a.
?- SolutionsSeen = [a], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [a],
X = b.
?- SolutionsSeen = [a, b], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [a, b],
X = c.
?- SolutionsSeen = [a, b, c], foo(X), \+ member(X, SolutionsSeen), !.
false.
So given a list of solutions we've seen before, we can force Goal to backtrack until it gives us one that we haven't seen before. Note that these queries are independent: In each one we have a completely fresh copy of the foo(X) goal that starts enumerating from a.
We can do the same thing programmatically by copying the original goal before calling it, forcing it to start a fresh enumeration from a fresh instance of the Goal. If this finds a new solution, we can add it to our solutions, then repeat with another fresh copy of the goal, forcing it to enumerate yet another new solution, and so on:
stupid_setof(Template, Goal, SolutionsSeen, Set) :-
copy_term(Goal-Template, GoalInstance-Solution),
call(GoalInstance),
\+ member(Solution, SolutionsSeen),
!,
stupid_setof(Template, Goal, [Solution | SolutionsSeen], Set).
If Goal has N answers, this will enumerate on the order of N**2 of them and do corresponding linear searches in the solutions list. It will also perform any side effects that Goal has multiple times.
But it "works":
?- stupid_setof(X, foo(X), Xs).
Xs = [a, b, c].
And, despite all of its stupidity, this is still less stupid than the standard setof/3 if Goal has no solutions:
:- dynamic bar/1. % no clauses
?- setof(X, bar(X), Set).
false.
?- stupid_setof(X, bar(X), Set).
Set = [].

What does Prolog assert/1 do with the term it is passed?

I'm trying to understand what assert and retract do with the term they are passed. If I run the following:
?- assertz(item(first)).
true.
?- assertz(item(second)).
true.
?- assertz((item(Y) :- =(Y, third), writeln(Y))).
true.
?- retract(item(X)).
X = first ;
X = second ;
false.
retract/1 removes all of the items but my writeln/1 is never called, so it appears retract is not actually resolving the term it is passed. It looks like it is doing some special operation where it:
Unifies the term with only facts (i.e. rules with no tail) in the database
Retracts each one after applying the substitution from unification
Is this right? Or is something else happening here?
Said another way: If I write my own single argument rule, Prolog does not automatically unify item(X) with the database and iterate through all facts that are item/1. It just gives me item(X). How is retract doing its magic?
?- assertz((myRule(X) :- writeln(X))).
true.
? myRule(item(X)).
item(_2556)
true.
Answer with further clarification:
Based on the answer by User9213, it appears that the answer is "retract (but not assert!) has a funny behavior where it does a simple unification of its term before it does something to the database". I'm left wondering why other built-in functions that I've seen (like atom/1 and writeln/1) don't appear to do this. Maybe it is more common than I've experienced?
For consistency, it seems like retract should have required ground terms and if the user wanted to do something like my above example, they could have done this:
?- (item(X), retract(item(X))).
It all makes me think I'm missing something or maybe these built in functions were just inconsistently designed? Any clarification that would explain that would be great.
To add my voice to the chorus, yes, all these predicates (assert*, retract*) manipulate the Prolog database of facts and rules; they do not evaluate their arguments as if they were facts or rules. Yes, they just do "syntactic" unification between their argument and the facts and rules in the database.
Prolog is a homoiconic language. The program can be manipulated as if it was data; the data structures can be interpreted as if they were the program. Most importantly: whether a certain structure is data or program depends only on the context.
You seem to understand this, but for the next poor soul that stumbles across your question and this answer, here is a toy example to demonstrate.
There is a built-in predicate atom/1 that succeeds if its argument is, well, an atom:
?- atom(foo).
true.
?- atom(Bar). % Bar is a free variable, which is not an atom
false.
?- atom(atom(bar)). % atom(bar) is a compound term, which is not an atom
false.
But atom(bar) is just a compound term in the last query. It is a compound term with a functor atom/1. Its only argument is an atom. So if you now queried it:
?- atom(bar).
true.
There is also this really nice predicate called call. It makes it even easier to blur the lines between program and data. The following three queries are identical in meaning:
?- atom(bar).
true.
?- call(atom, bar).
true.
?- call(atom(bar)).
true.
In addition, you can dynamically (at run-time) create a data structure and evaluate it as program. Here is a naive implementation of call/2 that can evaluate predicates, provided a predicate name and a list of arguments. It constructs the compound term using "univ" and evaluates it by just placing it in a slot where a subgoal is supposed to be. I'll call it my_call/2 and I will add it to the database using assertz:
?- assertz((my_call(Name, Args) :- Goal =.. [Name|Args], Goal)).
true.
?- my_call(between, [1, 3, X]).
X = 1 ;
X = 2 ;
X = 3.
Do you see what is going on? (Note: it seems that call is a relatively new addition to Prolog. Before call was widely available, you had to do this trick if you wanted to meta-call predicates. I don't know this from experience, just educated guessing based on things I've read or heard and can't be bothered to cite right now.)
So, let's try that again. In reality things are more complicated, but very simplified:
A Prolog program is a set of predicates. Not ordered!
Each predicate is a list of clauses. It is a list because a predicate may have 0 or more clauses, and they have order.
A clause can be a fact or a rule.
A rule is a compound term with functor :-/2. Yes, this is right. To see what I mean:
?- assertz(:-(foo(X), between(1, 3, X))).
true.
?- listing(foo/1).
:- dynamic foo/1.
foo(A) :-
between(1, 3, A).
true.
This is just another way to write it. It is more conventional.
So indeed, these two are very different:
foo(X). % a fact
foo(X) :- between(1, 3, X). % a rule
You cannot unify the one with the other. This is why, if you want to retract foo(X) :- between(1, 3, X), you cannot just pass foo(X) as the argument to retract. Or, to complete your example:
?- assertz(item(first)).
true.
?- assertz(item(second)).
true.
?- assertz((item(Y) :- =(Y, third), writeln(Y))).
true.
?- retract(item(X)).
X = first ;
X = second ;
false.
?- retract((item(X) :- X = Y, writeln(X))).
Y = third.
Do you see it now?
I had a vague memory of there being a retractall/1 that lives alongside retract/1 and it turns out the reason for it is situations like this. retract/1 accepts a Prolog term, as the documentation states:
retract(+Term)
When Term is an atom or a term it is unified with the first unifying fact or clause in the database. The fact or clause is removed from the database.
Emphasis added by me.
This is illustrated by the following:
?- asserta(foo(X) :- X = 2 ; X = 4).
true.
?- foo(X).
X = 2 ;
X = 4.
?- retract(foo(X)).
false.
?- foo(X).
X = 2 ;
X = 4.
?- retract(foo(X) :- X = 2 ; X = 4).
true.
?- foo(X).
false.
Note that if you furnish the complete clause you gave to asserta/1, it will be retracted. As #CapelliC points out below, you can also furnish a clause with a variable as a parameter to retract things with bodies:
retract(foo(X) :- Y).
However, if you do want to retract things that match a pattern, you can use retractall/1, which the documentation states:
retractall(+Head)
All facts or clauses in the database for which the head unifies with Head are removed.
This is illustrated by the following:
?- asserta(foo(X) :- X = 2 ; X = 4).
true.
?- foo(X).
X = 2 ;
X = 4.
?- retractall(foo(X)).
true.
?- foo(X).
false.
Another important difference between these two is that retract/1 will remove one thing at a time, and it will unify those things:
?- asserta(foo(X) :- X = 2).
true.
?- asserta(foo(X) :- X = 4).
true.
?- retract(foo(X) :- Y).
Y = (X=4) ;
Y = (X=2) .
This is in contrast to retractall/1 which will remove everything that matches the pattern, without unifying anything:
?- asserta(foo(X) :- X=2).
true.
?- asserta(foo(X) :- X=4).
true.
?- foo(X).
X = 4 ;
X = 2.
?- retractall(foo(X)).
true.
?- foo(X).
false.
So, retract/1 is really for doing one-at-a-time retractions but expects something shaped like the term you asserted, whereas retractall/1 only wants a head, treats it as a pattern, and will remove as many things as match the pattern.
This certainly helped me improve my understanding of Prolog, so I hope it helps you as well!
The definition of assert in swi-prolog is:
Assert a clause (fact or rule) into the database. The predicate asserta/1 asserts the clause as first clause of the predicate while assertz/1 assert the clause as last clause. The deprecated assert/1 is equivalent to assertz/1. If the program space for the target module is limited (see set_module/1), asserta/1 can raise a resource_error(program_space) exception. The example below adds two facts and a rule. Note the double parentheses around the rule.
Hence, it does not call or infer anything! It's just an assertion for the fact and the rule into the active memory.

prolog doesn't give me a solution when one exists

I am working through Seven Languages in Seven Weeks, but there is something I don't understand about prolog. I have the following program (based on their wallace and grommit program):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
and load it like this
?- ['teams.pl'].
true.
but it doesn't give me any solutions to the following
?- teamMate(a, X).
false.
it can solve simpler stuff (which is shown in the book):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
and there are solutions:
?- teamMate(a, b).
true ;
false.
What am I missing? I have tried with both gnu prolog and swipl.
...AND THERE IS MORE...
when you move the "can't be your own teammate" restriction to then end:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
it gives me the solutions I would expect:
?- ['teams.pl'].
true.
?- teamMate(a, X).
X = b.
?- teamMate(b, X).
X = a ;
X = c.
What gives?
You have made a very good observation! In fact, the situation is even worse, because even the most general query fails:
?- teamMate(X, Y).
false.
Declaratively, this means "there are no solutions whatsoever", which is obviously wrong and not how we expect relations to behave: If there are solutions, then more general queries must not fail.
The reason you get this strange and logically incorrect behaviour is that (\+)/1 is only sound if its arguments are sufficiently instantiated.
To express disequality of terms in a more general way, which works correctly no matter if the arguments are instantiated or not, use dif/2, or, if your Prolog system does not provide it, the safe approximation iso_dif/2 which you can find in the prolog-dif tag.
For example, in your case (note_that_I_am_using_underscores_for_readability instead of tuckingTheNamesTogetherWhichMakesThemHarderToRead):
team_mate(X, Y) :- dif(X, Y), on_team(X, Z), on_team(Y, Z).
Your query now works exactly as expected:
?- team_mate(a, X).
X = b.
The most general query of course also works correctly:
?- team_mate(X, Y).
X = a,
Y = b ;
X = b,
Y = a ;
X = b,
Y = c ;
etc.
Thus, using dif/2 to express disequality preserves logical-purity of your relations: The system now no longer simply says false even though there are solutions. Instead, you get the answer you expect! Note that, in contrast to before, this also works no matter where you place the call!
The answer by mat gives you some high-level considerations and a solution. My answer is a more about the underlying reasons, which might or might not be interesting to you.
(By the way, while learning Prolog, I asked pretty much the same question and got a very similar answer by the same user. Great.)
The proof tree
You have a question:
Are two players team mates?
To get an answer from Prolog, you formulate a query:
?- team_mate(X, Y).
where both X and Y can be free variables or bound.
Based on your database of predicates (facts and rules), Prolog tries to find a proof and gives you solutions. Prolog searches for a proof by doing a depth-first traversal of a proof tree.
In your first implementation, \+ (X = Y) comes before anything else, so it at the root node of the tree, and will be evaluated before the following goals. And if either X or Y is a free variable, X = Y must succeed, which means that \+ (X = Y) must fail. So the query must fail.
On the other hand, if either X or Y is a free variable, dif(X, Y) will succeed, but a later attempt to unify them with each other must fail. At that point, Prolog will have to look for a proof down another branch of the proof tree, if there are any left.
(With the proof tree in mind, try to figure out a way of implementing dif/2: do you think it is possible without either a) adding some kind of state to the arguments of dif/2 or b) changing the resolution strategy?)
And finally, if you put \+ (X = Y) at the very end, and take care that both X and Y are ground by the time it is evaluated, then the unification becomes more like a simple comparison, and it can fail, so that the negation can succeed.

How to properly express inequality in prolog?

TL;DR: sibling(a,X) succeeds with the answer X = a, but sibling(a,a) fails.
I have the following Prolog file:
children(a, c).
children(a, d).
children(b, c).
children(b, d).
sibling(X, Y) :-
X \== Y, A \== B,
children(X, A), children(X, B),
children(Y, A), children(Y, B).
It seems clear enough to me, two person are siblings if their parents are the same. Also, a person is not their own sibling.
But when I tried to run some queries on GNU Prolog, I get some strange results:
| ?- sibling(a, b).
true ? a
true
true
yes
This is the intended behavior. a and b are siblings. There are three results, which is a bit weird, but I assume Prolog is binding A = c, B = d and A = d, B = c.
| ?- sibling(a, a).
no
I think this means a and a are not siblings.
| ?- sibling(a, X).
X = a ? a
X = b
X = a
X = b
X = a
X = b
X = a
X = b
(15 ms) yes
This is where I got stuck: It says X = a, which means sibling(a,a) is true, but sibling(a,a) failed in the previous query!
I feel that I'm not understanding what \== actually does in Prolog.
What is happening, and how do I fix this?
TL;DR: Use prolog-dif—or iso_dif/2 (on iso-prolog conforming systems like gnu-prolog)!
Good question, +1!
In fact, it's a question I have asked myself, and the answer has to do with logical-purity: logical purity is a central aspect of what
makes Prolog as a language so special, as it enables you to:
describe—not prescribe
write code that is relational—not just functional
think in terms of problems / solutions—not the individual steps of the search process itself
operate on a higher level—not get lost in nitty-gritty details
Unlike many other programming languages, Prolog programs have both procedural semantics (defining the execution steps and their order) and declarative semantics (allowing you to state relations that should hold and let the Prolog processor find a proper way of execution by itself).
But, beware: Prolog has some features that, when used, ruin declarative semantics. To prevent this, try to structure your application into two parts: an impure shell for dealing with side-effects (input/output) and a logically pure base which comprises pure monotonic Prolog code.
Try moving the inequality to the end of the predicate. Maybe it gives you true because it's not instantiated already.
sibling(X,Y):- children(X, A), children(X, B),
children(Y, A), children(Y, B),
X \== Y, A \== B.

Prolog: Error out of global stack with what looks like ONE level of recursion to me

I am quite rusty in prolog, but I am not sure why things like this fail:
frack(3).
frack(X) :- frack(X-1).
So, if I evaluate frack(4). from the interactive prompt with the above facts defined, I expect that it should not have to endlessly recurse, since 4-1 = 3. But I get this error in SWI-Prolog:
ERROR: Out of global stack
Try it:
?- 4-1 = 3.
false.
Why? Because 4-1 = -(4, 1), which clearly is not a number but a compound term.
To reason about integers in Prolog, use clpfd constraints, for example (using GNU Prolog or B-Prolog):
| ?- 4-1 #= X.
X = 3
In SWI-Prolog, the graphical tracer may be useful for you to see what happens:
?- gtrace, frack(4).
For more complex debugging, I recommend failure-slice as shown in false's answer.
Here is the reason for this non-termination. Your query does not terminate, because there is a failure-slice of your program that does not terminate:
?- frack(4).
frack(3) :- false.
frack(X) :-
frack(X-1), false.
You can fix this only by modifying something in the visible part. Three SO-answers suggest to use (is)/2. But this will not remove non-termination! In fact, using (is)/2 leads to essentially the same fragment:
?- frack(4).
frack(3) :- false.
frack(X) :-
Y is X - 1,
frack(Y), false.
At least, frack(4) now succeeds, but it will loop on backtracking. You have to change something in the visible part, like some test for X, in order to avoid non-termination. See failure-slice for more.
frack(X) :- frack(X-1).
should be
frack(X) :- Y is X - 1, frack(Y).
The way you wrote it, X-1 expression of the first level unifies with X variable at the next level, never going for the frack(3) fact.
Prolog doesn't do arithmetic unless you use the is operator:
frack(X) :- X1 is X-1, frack(X1).

Resources