prolog - infinite rule - prolog

I have the next rules
% Signature: natural_number(N)/1
% Purpose: N is a natural number.
natural_number(0).
natural_number(s(X)) :-
natural_number(X).
ackermann(0, N, s(N)). % rule 1
ackermann(s(M),0,Result):-
ackermann(M,s(0),Result). % rule 2
ackermann(s(M),s(N),Result):-
ackermann(M,Result1,Result),
ackermann(s(M),N,Result1). % rule 3
The query is: ackermann (M,N,s(s(0))).
Now, as I understood, In the third calculation, we got an infinite search (failure branch). I check it, and I got a finite search (failure branch).
I'll explain: In the first, we got a substitution of M=0, N=s(0) (rule 1 - success!). In the second, we got a substitution of M=s(0),N=0 (rule 2 - success!). But what now? I try to match M=s(s(0)) N=0, But it got a finite search - failure branch. Why the compiler doesn't write me "fail".
Thank you.

It was a bit hard to understand exactly what Tom is asking here. Perhaps there's an expectation that the predicate natural_number/1 somehow influences the execution of ackermann/3. It will not. The latter predicate is purely recursive and makes no subgoals that depend on natural_number/1.
When the three clauses shown are defined for ackermann/3, the goal:
?- ackermann(M,N,s(s(0))).
causes SWI-Prolog to find (with backtracking) the two solutions that Tom reports, and then to go into infinite recursion (resulting in an "Out of Stack" error). We can be sure that this infinite recursion involves the third clause given for ackermann/3 (rule 3 per Tom's comments in code) because in its absence we only get the two acknowledged solutions and then explicit failure:
M = 0,
N = s(0) ;
M = s(0),
N = 0 ;
false.
It seems to me Tom asks for an explanation of why changing the submitted query to one that sets M = s(s(0)) and N = 0, producing a finite search (that finds one solution and then fails on backtracking), is consistent with the infinite recursion produced by the previous query. My suspicion here is that there's a misunderstanding of what the Prolog engine attempts in backtracking (for the original query), so I'm going to drill down on that. Hopefully it clears up the matter for Tom, but let's see if it does. Admittedly my treatment is wordy, but the Prolog execution mechanism (unification and resolution of subgoals) is worthy of study.
[Added: The predicate has an obvious connection to the famous Ackermann function that is total computable but not primitive recursive. This function is known for growing rapidly, so we need to be careful in claiming infinite recursion because a very large but finite recursion is also possible. However the third clause puts its two recursive calls in an opposite order to what I would have done, and this reversal seems to play a critical role in the infinite recursion we find in stepping through the code below.]
When the top-level goal ackermann(M,N,s(s(0))) is submitted, SWI-Prolog tries the clauses (facts or rules) defined for ackermann/3 until it finds one whose "head" unifies with the given query. The Prolog engine does not have far to look as the first clause, this fact:
ackermann(0, N, s(N)).
will unify, binding M = 0 and N = s(0) as has already been described as the first success.
If requested to backtrack, e.g. by user typing semi-colon, the Prolog engine checks to see if there is an alternative way to satisfy this first clause. There is not. Then the Prolog engine proceeds to attempt the following clauses for ackermann/3 in their given order.
Again the search does not have to go far because the second clause's head also unifies with the query. In this case we have a rule:
ackermann(s(M),0,Result) :- ackermann(M,s(0),Result).
Unifying the query and the head of this rule yields the bindings M = s(0), N = 0 in terms of the variables used in the query. In terms of the variables used in the rule as stated above, M = 0 and Result = s(s(0)). Note that unification matches terms by their appearance as calling arguments and does not consider variable names reused across the query/rule boundary as signifying identity.
Because this clause is a rule (having body as well as head), unification is just the first step in trying to succeed with it. The Prolog engine now attempts the one subgoal that appears in the body of this rule:
ackermann(0,s(0),s(s(0))).
Note that this subgoal comes from replacing the "local" variables used in the rule by the values of unification, M = 0 and Result = s(s(0)). The Prolog engine is now calling the predicate ackermann/3 recursively, to see if this subgoal can be satisfied.
It can, as the first clause (fact) for ackermann/3 unifies in the obvious way (indeed in essentially the same way as before as regards the variables used in the clause). And thus (upon this recursive call succeeding), we get the second solution succeeding in the outer call (the top-level query).
If the user asks the Prolog engine to backtrack once more, it again checks to see if the current clause (the second one for ackermann/3) can be satisfied in an alternative way. It cannot, and so the search continues by passing to the third (and last) clause for predicate ackermann/3:
ackermann(s(M),s(N),Result) :-
ackermann(M,Result1,Result),
ackermann(s(M),N,Result1).
I'm about to explain that this attempt does produce infinite recursion. When we unify the top-level query with the head of this clause, we get bindings for the arguments that can perhaps be clearly understood by aligning the terms in in the query with those in the head:
query head
M s(M)
N s(N)
s(s(0)) Result
Bearing in mind that variables having the same name in the query as variables in the rule does not constrain unification, this triple of terms can be unified. Query M will be head s(M), that is a compound term involving functor s applied to some as-yet unknown variable M appearing in the head. Same thing for query N. The only "ground" term so far is variable Result appearing in the head (and body) of the rule, which has been bound to s(s(0)) from the query.
Now the third clause is a rule, so the Prolog engine must continue by attempting to satisfy the subgoals appearing in the body of that rule. If you substitute values from the head unification into the body, the first subgoal to satisfy is:
ackermann(M,Result1,s(s(0))).
Let me point out that I've used here the "local" variables of the clause, except that I've replaced Result by the value to which it was bound in unification. Now notice that apart from replacing N of the original top-level query by variable name Result1, we are just asking the same thing as the original query in this subgoal. Certainly it's a big clue we might be about to enter an infinite recursion.
However a bit more discussion is needed to see why we don't get any further solutions reported! This is because the first success of that first subgoal is (just as found earlier) going to require M = 0 and Result1 = s(0), and the Prolog engine must then proceed to attempt the second subgoal of the clause:
ackermann(s(0),N,s(0)).
Unfortunately this new subgoal does not unify with the first clause (fact) for ackermann/3. It does unify with the head of the second clause, as follows:
subgoal head
s(0) s(M)
N 0
s(0) Result
but this leads to a sub-subgoal (from the body of the second clause):
ackermann(0,s(0),s(0)).
This does not unify with the head of either the first or second clause. It also does not unify with the head of the third clause (which requires the first argument to have the form s(_)). So we reached a point of failure in the search tree. The Prolog engine now backtracks to see if the first subgoal of the third clause's body can be satisfied in an alternative way. As we know, it can be (since this subgoal is basically the same as the original query).
Now M = s(0) and Result1 = 0 of that second solution leads to this for the second subgoal of the third clause's body:
ackermann(s(s(0)),N,0).
While this does not unify with the first clause (fact) of the predicate, it does unify with the head of the second clause:
subgoal head
s(s(0)) s(M)
N 0
0 Result
But in order to succeed the Prolog engine must satisfy the body of the second clause as well, which is now:
ackermann(s(s(0)),s(0),0).
We can easily see this cannot unify with the head of either the first or second clause for ackermann/3. It can be unified with the head of the third clause:
sub-subgoal head(3rd clause)
s(s(0)) s(M)
s(0) s(N)
0 Result
As should be familiar now, the Prolog engine checks to see if the first subgoal of the third clause's body can be satisfied, which amounts to this sub-sub-subgoal:
ackermann(s(0),Result1,0).
This fails to unify with the first clause (fact), but does unify with the head of the second clause binding M = 0, Result1 = 0 and Result = 0 , producing (by familiar logic) the sub-sub-sub-subgoal:
ackermann(0,0,0).
Since this cannot be unified with any of the three clauses' heads, this fails. At this point the Prolog engine backtracks to trying to satisfy the above sub-sub-subgoal using the third clause. Unification goes like this:
sub-sub-subgoal head(3rd clause)
s(0) s(M)
Result1 s(N)
0 Result
and the Prolog engine's task is then to satisfy this sub-sub-sub-subgoal derived from the first part of the third clause's body:
ackermann(0,Result1,0).
But this will not unify with the head of any of the three clauses. The search for a solution to the sub-sub-subgoal above terminates in failure. The Prolog engine backtracks all the way to where it first tried to satisfy the second subgoal of the third clause as invoked by the original top-level query, as this has now failed. In other words it tried to satisfy it with the first two solutions of the first subgoal of the third clause, which you will recall was in essence the same except for change of variable names as the original query:
ackermann(M,Result1,s(s(0))).
What we've seen above are that solutions for this subgoal, duplicating the original query, from the first and second clauses of ackermann/3, do not permit the second subgoal of the third clause's body to succeed. Therefore the Prolog engine tries to find solutions that satisfy the third clause. But clearly this is now going into infinite recursion, as that third clause will unify in its head, but the body of the third clause will repeat exactly the same search we just chased through. So the Prolog engine now winds up going into the body of the third clause endlessly.

Let me rephrase your question: The query ackermann(M,N,s(s(0))). finds two solutions and then loops. Ideally, it would terminate after these two solutions, as there is no other N and M whose value is s(s(0)).
So why does the query not terminate universally? Understanding this can be quite complex, and the best advice is to not attempt to understand the precise execution mechanism. There is a very simple reason: Prolog's execution mechanism turns out to be that complex that you easily will misunderstand it anyway if you attempt to understand it by stepping through the code.
Instead, you can try the following: Insert goals false at any place in your program. If the resulting program does not terminate, then also the original program will not terminate.
In your case:
ackermann(0, N, s(N)) :- false.
ackermann(s(M),0,Result):- false,
ackermann(M,s(0),Result).
ackermann(s(M),s(N),Result):-
ackermann(M,Result1,Result), false,
ackermann(s(M),N,Result1).
We can now remove the first and second clause. And in the third clause, we can remove the goal after false. So if the following fragment does not terminate, also the original program will not terminate.
ackermann(s(M),s(N),Result):-ackermann(M,Result1,Result), false.
This program now terminates only if the first argument is known. But in our case it's free...
That is: By considering a small fraction of the program (called a failure-slice) we already were able to deduce a property of the entire program. For details, see this paper and others on the site.
Unfortunately, that kind of reasoning only works for cases of non-termination. For termination, things are more complex. The best is to try a tool like cTI which infers termination conditions and tries to prove their optimality. I entered your program already, so try to modify if and see the effects!
If we are at it: This small fragment also tells us that the second argument does not influence termination1. That means, that queries like ackermann(s(s(0)),s(s(0)),R). will
not terminate either. Exchange the goals to see the difference...
1 To be precise, a term that does not unify with s(_) will influence termination. Think of 0. But any s(0), s(s(0)), ... will not influence termination.

Related

Prolog: compare three lists, 1st element of list1 to last element of list2 AND second to last element of list3

Write a PROLOG program (i.e., set of predicates) that implements the following function. The program should compare three lists and determine if the first element of the first list is the same as both the last element of the second list and the second to last element of the third list. Call the main predicate: compare(List1, List2, List3).
I went ahead and wrote separate codes for the two separate conditions, which works on its own.
1. 1st item of List1 equals last item of List2.
2. 1st item of List1 equals second to last item of List3.
Now I'm having trouble combining the codes to work together. My train of thought is that condition 1 and condition 2 have to be met separately before the overall condition is met. So somehow I have to run the code for condition 1 and condition 2 on its own but in the same program?? And if both of those return true then I can have something else that says my conditions are met.
compare(List1,List2,List3):- last(true), secondLast(true).
Condition1:
last([HeadList1|RestList1],[HeadList1]).
last([HeadList1|RestList1],[HeadList2|RestList2]) :-
last([HeadList1|RestList1],RestList2).
Condition2:
secondLast([HeadList1|RestList1],[HeadList1,RestList3]).
secondLast([HeadList1|RestList1],[HeadList3|RestList3]) :-
secondLast([HeadList1|RestList1],RestList3).
What I'm expecting:
?- compare([2,8,9,1],[4,5,6,2],[1,2,3]).
yes
?- compare([a,b,c,d,k],[a,c,f,e],[a,s]).
no
With SWI, you can use last/2 and the definition of secondTast/2 from this question:
secondLast([X,_], X).
secondLast([_|T], X) :- secondLast(T, X).
my_compare([H|_],L1,L2):-
last(L1,H),
secondLast(L2,H).
?- my_compare([2,8,9,1],[4,5,6,2],[1,2,3]).
true
?- my_compare([a,b,c,d,k],[a,c,f,e],[a,s]).
false
You can put a cut to avoid the solution false in the first query. This is a first solution, you can get super fancy and use for instance reverse/2 and other predicates to find another solution (but maybe slower).
#damianodamiano suggests an implementation using reverse/2 and I thought it might be interesting to see what it is.
mycompare([H|_], L2, L3) :-
reverse(L2, [H|_]),
reverse(L3, [_, H|_]).
reverse/2 is somewhat more expensive than a list traversal, so this may not be the best way to solve the problem, I think it's worth seeing because it's fairly close to the question as stated and it demonstrates that this problem is solved really by unification and only unification. damianodamiano's solution has a similar property in that you are finding the first thing, H and then showing that H appears in other positions in the other two lists.
Now I have some miscellaneous feedback for you:
You are right to believe that if you have two predicates, say p1 and p2, you can combine them by doing p1, p2. In general, they are going to share variable bindings between them because what you are doing in programming in Prolog is setting up a relationship between certain things.
This is also why singleton "warnings" are actually errors: they reveal cases where you believe there is a relationship, but where Prolog could tell that you didn't share the variable anywhere, so no relationship was established.
Your variable names are really bad. If 99% of all your variable names are the same, you are going to get confused. It would be better to use A and B than HeadList1 and HeadList2. If you must use names like these, simplify to H1 and H2. When you see [X|Y], you know X is a head of a list and Y is a list tail, you do not need to make that information part of the name. Focus on the content of the variable if you can, or the relationship you're trying to establish between the expressions that variable is a part of.
Prolog predicates do not "return true." They can succeed or fail but they are not evaluated like functions: you cannot replace mycompare(A,B,C) with true just because mycompare(A,B,C) succeeds, you cannot assign a value to the result R = mycompare(A,B,C), and you cannot nest predicates like writeln(mycompare(A,B,C)). So break this habit now so you don't confuse yourself further in the future.

How do recursive functions work in Prolog?

I was reading a recursive function in prolog that returns the Sum of all the elements in a list as below :
sum([ ], 0).
sum( [Elem | Tail], S):- sum(Tail, S1),
S is S1 + Elem.
I can't understand two issues:
1: In the left side of ":-" we have the Goal. It means all the calculations will be done in the right side of ":-" and then we can use the Goal as a normal function. It means we give our arguments and variables that the result will be putted on them, and the right side is responsible for calculating.
But in this code the Goal, itself is calculating the Head and Tail. I mean in my mind the code should have been like this (however it doesn't work!) :
sum(Tail, S1):-sum( [Elem | Tail], S),........
Because the goal is supposed to give the arguments and the right side is in charge of calculating.
2: I cannot understand how this code works step by step. can anyone give me a very simple example like how it calculates the sum of [1,2,3]?
In the left side of :- you have a head of the rule; on the right side you have the body of the rule. When the :- side and the body are missing, the rule becomes a fact.
It is not correct to say that the calculation is performed only in the body, because the decision making process of Prolog works with both sides of the rule. The concept where the head of the rule plays an important role is unification, a process by which the language decides which clauses are applicable to the query, and makes checks and temporary assignments of variables in the rule head to parts of the query ("unifies" them).
For example, when you query sum([1,2,3], X), Prolog checks both sum clauses, and decides that the query unifies only with the second one, because [] cannot be unified with [1,2,3].
Now it needs to unify [1,2,3] with [Elem | Tail] by making a temporary assignment that lasts for as long as we are in the body of the rule: Elem=1, and Tail = [2,3]. At this point it tries to solve sum again, passing [2,3] as the first parameter. The first rule does not match, so another temporary assignment of Elem=2 and Tail=[3] is made. In the third level of recursion we reach an assignment Elem=3 and Tail=[]. This is when we hit the first rule, producing an assignment of S1=0. Third level of invocation adds 3 to it; second level adds 2. First level adds 1, and returns with X set to 6.
An important part of prolog is matching (more generally, unification). When the Prolog run-time encounters a goal like sum(X,Y), it will try to match that term with the left-hand sides (head) of the rules for sum, in the order in which they appear. If the first rule fails, then the system will move to the second rule and so on.
In this case, the first head will only match if X is the empty list. If it is not empty, the match fails, and the next head is tried. This will succeed as long as X is any non empty list. Not only will it succeed, but it will bind the first element of the list to Elem , the rest of the list (which may be empty) to Tail. Since the second argument in the head of this rule is a variable, it will bind to whatever Y is.
Let's work through some examples:
sum([],X)?
First head matches, binding X to 0.
sum([1],X)?
First head does not match because [1] does not match []. Second one does with Elem <- 1, Tail<-[]. Therefore, we can proceed with the right-hand side of the rule:
sum(Tail,S1), S is S1 + Elem
Since Tail<-[] , the goal sum(Tail,S1) will yield the binding S1<-0 (see above). So with Elem<-1 and S1<-0, S1+Elem = 1.
And so on. Hopefully there is enough here for you to do the rest.
Your speculations about what happens during the execution are rather strange. No functions are involved at all.
For the evaluation of the goal sum([1,2,3], X), the second clause is selected because there is no matching between [1,2,3] (first argument of the goal) and [] (in the head of the first clause).
The matching instantiates Elem=1, Tail=[2,3] and S = X. Then the goal sum([2,3], S1) is evaluated, and succeeds (after recursion), returning the substitution S1=5. Then S=5+1 binds S to 6.

Recursive procedure explanation

So I have the following working code in Prolog that produces the factorial of a given value of A:
factorial(0,1).
factorial(A,B) :- A>0, C is A-1, factorial(C,D), B is A*D.
I am looking for an explanation as to how this code works. I.e, what exactly happens when you ask the query: factorial(4, Answer).
Firstly,
factorial(0, 1).
I know the above is the "base case" of the recursive definition. What I am not sure of why/how it is the base case. My guess is that factorial(0, 1) inserts some structure containing (0, 1) as a member of "factorial". If so, what does the structure look like? I know if we say something like "rainy(seattle).", this means that Seattle is rainy. But "factorial(0, 1)"... 0, 1 is factorial? I realize it means factorial of 0 is 1, but how is this being used in the long run? (Writing this is helping me understand more as I go along, but I would like some feedback to make sure my thinking is correct.)
factorial(A,B) :- A>0, C is A-1, factorial(C,D), B is A*D.
Now, what exactly does the above code mean. How should I read it?
I am reading it as: factorial of (A, B) is true if A>0, C is A-1, factorial(C, D), B is A*D. That does not sound quite right to me... Is it?
"A > 0". So if A is equal to 0, what happens? It must not return at this point, or else the base case would never be used. So my guess is that A > 0 returns false, but the other functions are executed one last time. Did recursion stop because it reached the base case, or because A was not greater than 0? Or a combination of both? At what point is the base case used?
I guess that boils down to the question: What is the purpose of having both a base case and A > 0?
Sorry for the badly formed questions, thank you.
EDIT: In fact, I removed "A > 0" from the procedure and the code still works. So I guess my questions were not stupid at least. (And that code was taken from a tutorial.)
It is counterproductive to think of Prolog facts and rules in terms of data structures. When you write factorial(0, 1). you assert a fact to the Prolog interpreter that is assumed to be universally true. With this fact alone Prolog can answer questions of three types:
What is the factorial of 0? (i.e. factorial(0, X); the answer is X=1)
A factorial of what number is 1? (i.e. factorial(X,1); the answer is X=0)
Is it true that a factorial of 0 is 1? (i.e. factorial(0,1); the answer is "Yes")
As far as the rest of your Prolog program is concerned, only the first question is important. That is the question that the second clause of your factorial/2 rule will be asking at the end of evaluating a factorial.
The second rule uses comma operator, which is Prolog's way of saying "and". Your interpretation can be rewritten in terms of variables A and B like this:
B is a factorial of A when A>0, and C is set to A-1, and D is set to the factorial of C, and B is set to A times D
This rule covers all As above zero. The reference to factorial(C,D) will use the same rule again and again, until C arrives to zero. This is when this rule stops being applicable, so Prolog would grab the "base case" rule, and use 1 as its output. At this point, the chain of evaluating factorial(C, D) starts unwrapping, until it goes all the way to the initial invocation of the rule. This is when Prolog computes the final answer, and factorial/2 returns "Yes" and produces the desired output value.
In response to your edit, removing the A>0 is not dangerous only for getting the first result. Generally, you can ask Prolog to find you more results. This is when the factorial/2 with A>0 removed would fail spectacularly, because it would start going down the invocation chain of the second clause with negative numbers - a chain of calls that will end in numeric overflow or stack overflow, whichever comes first.
If you come from a procedural language background, the following C++ code might help. It mirrors pretty accurately the way the Prolog code executes (at least for the common case that A is given and B is uninstantiated):
bool fac(int a, int &b)
{
int c,d;
return
a==0 && (b=1,true)
||
a>0 && (c=a-1,true) && fac(c,d) && (b=a*d,true);
}
The Prolog comma operates like the sequential &&, and multiple clauses like a sequential ||.
My mental model for how prolog works is a tree traversal.
The facts and predicates in a prolog database form a forest of trees. When you ask the Prolog engine to evaluate a predicate:
?- factorial(6,N).
the Prolog engine looks for the tree rooted with the specified functor and arity (factorial/2 in this case). The Prolog engine then performs a depth-first traversal of that tree trying to find a solution using unification and pattern matching. Facts are evaluated as they are; For predicates, the right-hand side of the :- operator is evaluated, walking further into the tree, guided by the various logical operators.
Evaluation stops with the first successful evaluation of a leaf node in the tree, with the prolog engine remembering its state in the tree traversal. On backtracking, the tree traversal continues from where it left off. Execution is finally complete when the tree traversal is completed and there are no more paths to follow.
That's why Prolog is a descriptive language rather than an imperative language: you describe what constitutes truth (or falsity) and let the Prolog engine figure out how to get there.

Explanation of Prolog recursive procedure

I'd like someone to explain this procedure if possible (from the book 'learn prolog now'). It takes two numerals and adds them together.
add(0,Y,Y).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
In principle I understand, but I have a few issues. Lets say I issue the query
?- add(s(s(0)), s(0), R).
Which results in:
R = s(s(s(0))).
Step 1 is the match with rule 2. Now X becomes s(0) and Y is still s(0). However Z (according to the book) becomes s(_G648), or s() with an uninstantiated variable inside it. Why is this?
On the final step the 1st rule is matched which ends the recursion. Here the contents of Y somehow end up in the uninstantiated part of what was Z! Very confusing, I need a plain english explanation.
First premises:
We have s(X) defined as the successor of X so basically s(X) = X+1
The _G### notation is used in the trace for internal variables used for the recursion
Let's first look at another definition of addition with successors that I find more intuitive:
add(0,Y,Y).
add(s(A),B,C) :- add(A,s(B),C).
this does basically the same but the recursion is easier to see:
we ask
add(s(s(0)),s(0),R).
Now in the first step prolog says thats equivalent to
add(s(0),s(s(0)),R)
because we have add(s(A),B,C) :- add(A,s(B),C) and if we look at the question A = s(0) and B=s(0). But this still doesn't terminate so we have to reapply that equivalency with A=0 and B=s(s(0)) so it becomes
add(0,s(s(s(0))),R)
which, given add(0,Y,Y). this means that
R = s(s(s(0)))
Your definition of add basically does the same but with two recursions:
First it runs the first argument down to 0 so it comes down to add(0,Y,Y):
add(s(s(0)),s(0),R)
with X=s(0), Y = s(0) and s(Z) = R and Z = _G001
add(s(0),s(0),_G001)
with X = 0, Y=s(0) and s(s(Z)) = s(G_001) = R and Z = _G002
add(0,s(0),_G002)
So now it knows that _G002 is s(0) from the definition add(0,Y,Y) but has to trace its steps back so _G001 is s(_G002) and R is s(_G001) is s(s(_G002)) is s(s(s(0))).
So the point is in order to get to the definition add(0,Y,Y) prolog has to introduce internal variables for a first recursion from which R is then evaluated in a second one.
If you want to understand the meaning of a Prolog program, you might concentrate first on what the relation describes. Then you might want to understand its termination properties.
If you go into the very details of a concrete execution as your question suggests, you will soon be lost in the multiplicity of details. After all, Prolog has two different interlaced control flows (AND- and OR-control) and in addition to that it has unification which subsumes parameter passing, assignment, comparison, and equation solving.
Brief: While computers execute a concrete query effortlessly for zillions of inferences, you will get tired after a screenful of them. You can't beat computers in that. Fortunately, there are better ways to understand a program.
For the meaning, look at the rule first. It reads:
add(s(X),Y,s(Z)) :- add(X,Y,Z).
See the :- in between? It is meant to symbolize an arrow. It is a bit unusual that the arrow points from right-to-left. In informal writing you would write it rather left-to-right. Read this as follows:
Provided, add(X,Y,Z) is true, then also add(s(X),Y,s(Z)) is true.
So we assume that we have already some add(X,Y,Z) meaning "X+Y=Z". And given that, we can conclude that also "(X+1)+Y=(Z+1)" holds.
After that you might be interested to understand it's termination properties. Let me make this very brief: To understand it, it suffices to look at the rule: The 2nd argument is only handed further on. Therefore: The second argument does not influence termination. And both the 1st and 3rd argument look the same. Therefore: They both influence termination in the same manner!
In fact, add/3 terminates, if either the 1st or the 3rd argument will not unify with s(_).
Find more about it in other answers tagged failure-slice, like:
Prolog successor notation yields incomplete result and infinite loop
But now to answer your question for add(s(s(0)), s(0), R). I only look at the first argument: Yes! This will terminate. That's it.
Let's divide the problem in three parts: the issues concerning instantiation of variables and the accumulator pattern which I use in a variation of that example:
add(0,Y,Y).
add(s(X),Y,Z):-add(X,s(Y),Z).
and a comment about your example that uses composition of substitutions.
What Prolog applies in order to see which rule (ie Horn clause) matches (whose head unifies) is the Unification Algorithm which tells, in particular, that if I have a variable, let's say, X and a funtor, ie, f(Y) those two term unify (there is a small part about the occurs check to...check but nevermind atm) hence there is a substitution that can let you convert one into another.
When your second rule is called, indeed R gets unified to s(Z). Do not be scared by the internal representation that Prolog gives to new, uninstantiated variables, it is simply a variable name (since it starts with '_') that stands for a code (Prolog must have a way to express constantly newly generated variables and so _G648, _G649, _G650 and so on).
When you call a Prolog procedure, the parameters you pass that are uninstantiated (R in this case) are used to contain the result of the procedure as it completes its execution, and it will contain the result since at some point during the procedure call it will be instantied to something (always through unification).
If at some point you have that a var, ie K is istantiated to s(H) (or s(_G567) if you prefer), it is still partilally instantiated and to have your complete output you need to recursively instantiate H.
To see what it will be instantiated to, have a read at the accumulator pattern paragraph and the sequent one, tho ways to deal with the problem.
The accumulator pattern is taken from functional programming and, in short, is a way to have a variable, the accumulator (in my case Y itself), that has the burden to carry the partial computations between some procedure calls. The pattern relies on recursion and has roughly this form:
The base step of the recursion (my first rule ie) says always that since you have reached the end of the computation you can copy the partial result (now total) from your accumulator variable to your output variable (this is the step in which, through unification your output var gets instantiated!)
The recursive step tells how to create a partial result and how to store it in the accumulator variable (in my case i 'increment' Y). Note that in the recursive step the output variable is never changed.
Finally, concerning your exemple, it follows another pattern, the composition of substitutions which I think you can understand better having thought about accumulator and instantiation via unification.
Its base step is the same as the accumulator pattern but Y never changes in the recursive step while Z does
It uses to unify the variable in Z with Y by partially instantiating all the computation at the end of each recursive call after you've reached the base step and each procedure call is ending. So at the end of the first call the inner free var in Z has been substituted by unification many times by the value in Y.
Note the code below, after you have reached the bottom call, the procedure call stack starts to pop and your partial vars (S1, S2, S3 for semplicity) gets unified until R gets fully instantiated
Here is the stack trace:
add(s(s(s(0))),s(0),S1). ^ S1=s(S2)=s(s(s(s(0))))
add( s(s(0)) ,s(0),S2). | S2=s(S3)=s(s(s(0)))
add( s(0) ,s(0),S3). | S3=s(S4)=s(s(0))
add( 0 ,s(0),S4). | S4=s(0)
add( 0 ,s(0),s(0)). ______|

how to print more than one answer in prolog

the question is I have to print all the minimum starters, then the minimum main then the minimum dessert.
I wrote this
starter( greenSalad,10).
starter( seserSalad,20).
starter( tomatoSalad,10).
main( chicken,40).
main( pizza,30).
main( pasta,30).
dessert( raspberryCake,30).
dessert( fruitCake,20).
dessert( applepie,20).
min(Head,Tail,Head):- Head<Tail.
min(Head,Tail,Tail):- Tail<Head.
findmin([Only], Only).
findmin([Head|Tail], Minimum) :- findmin(Tail, TailMin), Minimum is
min(Head, TailMin).
**findMeal**2:-findall(Sp,starter(_,Sp),SList),findmin(SList,Spm),printStarter2(Spm),
findall(Mp,main(_,Mp),MList),findmin(MList,Mpm),printMain2(Mpm),
findall(Dp,dessert(_,Dp),DList),findmin(DList,Dpm),printDessert2(Dpm).
printStarter2(Spm):-starter(S,Spm),write(S),nl,fail.
printMain2(Mpm):-main(M,Mpm),write(M),nl,fail.
printDessert2(Dpm):-dessert(D,Dpm),write(D),nl,fail.
The PROBLEM is : this give all minimum starters, then stop without giving the minimum main and dessert
Prolog tests predicates in order of their appearance in clause. It does nessesery unifications that would make the condition true. When it tries to prove findMeal, it proves findall/3, which always prove true, but does necessary unifications, ie. SList is bound after that.
Then it proves findmin/2, which unifies Spm with 10, and leaves choice point. It reaches printStarter2, and it tries to prove it, so it prints the greensaled and fails (fail/0, at the end of clause). It goes back to choice points and unifies Spm with 'next' 10 (from tomatoSalad). Inference engine goes yet again to printStarter, prints and fails again. As there are no more choice points, and last choice point failed, the predicate is unprovable, so inference engine stops and prints 'fail'.
If you want to fix that, make it print all the minimum meals, break the findMeal predicate into three clauses:
findMeal :- findall(Sp,starter(_,Sp),SList),findmin(SList,Spm),printStarter2(Spm).
findMeal :- findall(Mp,main(_,Mp),MList),findmin(MList,Mpm),printMain2(Mpm).
findMeal :- findall(Dp,dessert(_,Dp),DList),findmin(DList,Dpm),printDessert2(Dpm).
This will force the inference engine to create choice points right at the start of proving predicate. First predicate will fail after the same scenario as above, but inference engine will have more choice points - next findMeal clause, and so on.
Also, you might want to add one more findMeal clause, an empty one:
findMeal.
So the predicate will prove true after three previous clauses will fail.

Resources