Have a curiosity related to Prolog predicate control.
Supposedly I have a predicate f(A,X) and g(B).
f(A,X):- a,b,c, g(X).
g(B):- true.
a - returns true
b - returns true.
c - returns false.
where a,b and c are random predicates.
How can I continue to evaluate g(X) in the predicate f(A,X) if c returns false?
If your intention is to define f(A,X) such that g(X) should be evaluated whether or not c fails, then either:
You could encode this using implication (->) and/or disjunction (;), or
f(A,X) doesn't need to be defined in terms of c. This assumes c has no side-effects (e.g., asserting database facts using assert, or printing IO to a stream) which alter the environment and which cannot be undone on failure of c, in which case the first option is preferable.
There are several alternatives for using disjunction, such as:
f(A,X) :- ((a, b, c) ; (a, b)), g(X).
This definition (above) doesn't depend on c at all, but it will always execute c (as long as a and b succeed). The disjunction (;) allows PROLOG to backtrack to try executing a, b again if c failed at all, and to continue onto g(X). Note that this is equivalent to:
f(A,X) :- a, b, c, g(X).
f(A,X) :- a, b, g(X).
In order for PROLOG not to backtrack to evaluate f(A,X) twice because of the second (identical) head predicate f(A,X) for every evaluation, you may choose to place a cut (!), if your implementation supports it, immediately after the c subgoal in the first clause. The cut is placed after c because we don't want the interpreter to commit to that choice of f(A,X) clause if c had failed, instead, we want the interpreter to fail out of this clause and to try the next one, to effectively ignore c and to continue processing g(X).
Also note that this solution relies on a and b having no side-effects, because when c fails, a and b are executed again. If all a, b, and c have side effects, you can try using implication:
f(A,X) :- a, b, (c -> g(X) ; g(X)).
This will also effectively always execute g(X) whether c fails or not, and will not execute a and b again if c fails. This single-clause definition will also not leave a choice-point like the previous suggestion.
I guess you could wrap c in ignore/1. Consider e.g.
?- false, writeln('Hello World!').
false.
?- ignore(false), writeln('Hello World!').
Hello World!
true.
But why would you want to continue if c fails? What's the use case?
I tested this code in SWI-Prolog, I'm not sure if other Prologs have false/0 and ignore/1.
The latter can be defined like this though:
ignore(Goal) :- Goal, !.
ignore(_).
Related
I was trying to practice Prolog, as suggested by my TA, I am trying to create the rule append3(A,B,C,D) which means D is the result of the append of A,B and C.
The definition of append(A,B,C) is given
append([],B,B).
append([X|A],B,[X|C]):-append(A,B,C).
So I simply wrote following, which makes sense to me, as the rule for append3
append3(A,B,C,D) :- append(A,B,X),append(X,C,D).
After, I tried some query, such as append3(A,B,C,[1,2,3]). Everything was fine in the beginning, it was giving me the right results. However, at one moment, I pressed ;, it went into an infinite loop trying to search another answer.
I am not really sure why this happens? I suppose that append3(A,B,C,D) is a very basic rule to define. Is there anything that I am missing or that I didn't consider?
How can I fix this problem?
Prolog's execution mechanism is pretty complex compared to command oriented programming languages a.k.a. imperative languages (short form: imps). Your TA has given you an excellent example where you can improve your mastery of Prolog.
First of all, you need to understand the termination behavior of append/3. The best way is via a failure-slice which helps you focus on the part that is relevant to termination. In this case it is:
append([],B,B) :- false.
append([X|A],B,[X|C]):-append(A,B,C), false.
This fragment or failure slice now terminates exactly in all cases where your original definition terminates! And since it is shorter, it makes understanding of termination a bit easier. Of course, this new program will no longer find answers like for append([a],[b],[a,b]) — it will fail in stead. But for termination alone it's perfect.
Now let's go through the arguments one by one:
argument needs to have a non-empty list element and will fail (and terminate) should the argument be [] or any other term. Non-termination may only occur with a partial list (that's a list with a variable instead of [] at the end like [a,b|L]) or just a variable.
argument is just the variable B. There is no way how this B might be different to any term. Thus, B has no influence on termination at all. It is termination neutral.
argument is essentially the same as the first argument. In fact, those arguments look quite symmetrical although they describe different things.
To summarize, if the first or the last argument is a (fully instantiated) list, append/3 will terminate.
Note that I just said if and not iff. After all, the first and third argument are a bit connected to each other via the variable X. Let's ignore that for this analysis.
Now, to a failure slice of your definition.
append3(A,B,C,D) :- append(A,B,X), false, append(X,C,D).
Note that D does no longer occur in the visible part! Therefore, the fourth argument has no influence on termination of this fragment. And since X occurs for the first time, only A has an influence on its termination. Therefore, if A is just a variable (or a partial list), the program will not terminate! No need to look any further. No need to look at screens full of traces.
To fix this for a query like your query append3(A,B,C,[1,2,3])., D has to influence the first goal somewhat.
One possible fix suggested by another answer would be to exchange the goals:
append3(A,B,C,D) :- append(X,C,D), false, append(A,B,X).
Let's look at the variables of append(X,C,D)! C is termination neutral, X occurs for the first time and thus has no influence on termination at all. Only D may make this goal terminate. And thus queries like append3([1],[2],[3], D) will now loop! What a bargain, exchanging non-termination in one case for another!
To make your program work for both cases, the first goal of append/3 must contain both D and at least one of A, B or C. Try to find it yourself! Here is the spoiler:
append3(A, B, C, D) :- append(A, BC, D), append(B, C, BC).
Now the first goal terminates if either A or D is a (fully instantiated) list. The second goal requires either B or BC to be a list. And BC comes from the first goal, which is a list if D is one.
Thus append3(A, B, C, D) terminates_if b(A), b(B) ; (D).
See another answer for more on termination, failure slices, and a technique I have not mentioned here, which is termination inference.
And, note that there are still more cases where the definitions terminate, although they are rather obscure like append([a|_],_,[b|_]) or append3([a|_],_,_,[b|_])) which both fail (and thus terminate) although they only have partial lists. Because of this it's terminates_if and not terminates_iff.
You need to flip the predicates append(A, B, X), append(X, C, D). Since all three variables A, B, and X are unbound in append(A, B, X) prolog tries to satisfy it and then constrain it with append(X, C, D) which will always fail after giving you existing solutions. So it enters an infinite loop.
Try just executing append(A, B, X). all of them unbound. Prolog should show you an infinite sequence of solutions, these fail in the next clause append(X, C, D).
Flip the predicates and you should be fine.
append3(A, B, C, D) :-
append(T, C, D),
append(A, B, T).
I need to know if variable is instantiated in a given rule, yet I'm not allowed to use var(X), and have no clue on how to do so.
To be specific, my rule gets 4 parameter (P, A, B, C).
If P, A, B, C are instantiated then my rule should "return" true iff (A+B)mod(P)=C(mod(P)).
If one of A B and C isn't isntantiated I should return what value of it will guarantee that (A+B)mod(P)=C(mod(P)). so for example if C isn't instantiated the rule should "return" (A+B)mod(P) as C, and similar behavoir if A or B are not instantiated. Writing each rule is easy, but how can I know which of the cases I'm at if I don't know whther a variable is instantiated or not? as mentioned before, I can't use var(X) or number(X) and so on, I can only assume that P is always instantiated.
Thanks in advance!
I think #mat answer is definitely the way to go to solve your problem.
However, if you want to check whether a variable is not instantiated without using builtin predicate var/1 which does exactly that (due to some restriction, e.g. your teacher explicitly prohibited it) you may use double negation twice to test for the ability to bound a variable without really instantiating it if it is not bound:
not_inst(Var):-
\+(\+(Var=0)),
\+(\+(Var=1)).
Test cases:
?- not_inst(X).
true.
?- not_inst(a).
false.
Testing manually whether or not something is instantiated makes it very hard to correctly handle all cases that can arise in practice. Almost invariably, your resulting code will behave incorrectly for certain instantiation patterns you have not thought about.
Luckily, there is a declarative solution for such problems: Constraints work correctly in all cases, no matter what is instantiated and what is not.
For example, use your Prolog system's CLP(FD) constraints to solve your task:
:- use_module(library(clpfd)).
same_sum_mod(A, B, C, P) :-
(A+B) mod P #= C mod P.
It works correctly in all directions, for example:
?- same_sum_mod(1, 2, 3, 3).
true.
?- same_sum_mod(1, B, 3, 2).
1+B#=_G823,
_G823 mod 2#=1.
?- same_sum_mod(1, 2, 3, P).
P in inf..-1\/1..sup,
3 mod P#=_G855,
3 mod P#=_G855.
And also check out the following case, where B is initially not instantiated, but its domain is known, and the constraint solver can deduce the single admissible solution:
?- B in 0..1, same_sum_mod(1, B, 3, 2).
B = 0.
Such cases cannot be handled by simple instantiation checks, but require reasoning about constraints.
See clpfd for more information about CLP(FD) constraints.
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.
How would I write the following in Prolog?
a -> b V c
In English that would be a implies that b or c (or both)
The clause
a => (b ; c) % ';' means 'or'
is not a Horn clause and hence cannot be represented in (pure) Prolog (see e.g Wikipedia). On the other hand (b ; c) => a is a Horn clause and can obviously be represented by two Prolog rules.
I'm not entirely sure what you want to do with with this implies statement. But I would have thought the following would suffice (bear in mind this is SICStus not swi, but at this low level I think it's all the same).
predicate(a, b).
predicate(a, c).
?- predicate(a, Then).
Then = b ;
Then = c ;
no
?- predicate(x, Then).
no
You could do more complicated checks to make sure a is never an unbound value (to prevent predicate(If, b). being true), but unless you're making a huge application then I'm sure good documentation would suffice.
Logically, "b or c" is the same thing as "b or c (or both)"
You can read about logical operators in Prolog here: http://rigaux.org/language-study/syntax-across-languages-per-language/Prolog.html
Can you explain a bit more please what you're trying to do with 'implies'?
How can I write the following rule in PROLOG: if P then not Q
I understand that you can easily write if P then Q the predicates like q(X) :- p(X), but how can you negate the q/1 predicate? I don't want to define new predicates with other semantics like non_q/1.
The clause "if P then not Q" is logically equivalent to the negative clause "not P OR not Q". As such it is a Horn clause without a positive literal, and as an application of the correspondence of SLD theorem proving and Horn clauses, can be represented in Prolog programming as a goal clause or "query":
?- P, Q.
Let's come back to this idea in a minute.
But the goal clause is perhaps not the sort of representation you have in mind. The facts and rules that constitute a Prolog "knowledgebase" are definite clauses, i.e. Horn clauses each with exactly one positive literal. "If P then not Q" has no positive literal, so in this sense it cannot be represented (as a definite clause).
The goal clause shown above "asks" if P and Q can both be proven. Prolog provides a notion of "negation as failure", so a more natural way to "ask" whether "not P OR not Q" holds would be:
?- not((P,Q)).
Then we would get success if either P or Q fails, and failure if both succeed.
However if your purpose is to assert the negation something in the knowledgebase, Prolog doesn't naturally support this. Depending on your application, there may be a reasonable way to work around the Prolog syntax and accomplish what is needed (there's always an unreasonable way to do it, as you've hinted as with a non_q predicate).
Have you ever heard about cut in Prolog?
Anyway I don't know much about Prolog standard, but in SWI-Prolog the symbol \+ means negation. I know it don't have to work in every Prolog's interpreter.
You can make the predicate negation with Prolog's cut. The predicate is defined like:
not(Goal) :- call(Goal),!,fail.
not(Goal).
It means that Goal can't be proven, not the Goal is false.
Maybe this Prolog & Cut link will be useful.
"...if P then not Q" can be represented via the -> if-then control-flow predicate (e.g., GNU) , along with the \+ negation (or 'not-provable') operator (e.g., GNU), as follows:
(P -> \+ Q),
Note that, typically, \+ will implement what is known as negation-as-failure; i.e., the subgoal/expression \+ Q will succeed iff Q cannot. Note that the evaluation of Q under \+ will not affect the bindings of any variables present in the expression Q at execution.
For example, consider:
foo(a).
bar(b).
Given these facts, the following hold:
foo(a) -> \+ bar(a). % succeeds, as bar(a) is not provable.
foo(a) -> \+ bar(b). % fails, as bar(b) is provable.
foo(a) -> \+ bar(X). % fails, as bar(X) is provable; note that X remains unbound.
foo(X) -> \+ bar(X). % succeeds, as bar(X) where X unified to 'a' isn't provable.
Implementing something akin to \+ q(X) :- p(X) as you might want (in terms of a 'rule') isn't straightforward, as you describe, however a potential hack is:
q(X) :- p(X), !, fail.
This definition will only reflect the intention that q(X) is to fail for all X where p(X) succeeds iff it is asserted before any other clauses of q(X), but may not be ideal.
You can use minimal logic to define a negative head. In minimal logic
~A can be viewed as A -> ff. Thus the following
P -> ~Q
Can be viewed as:
P -> (Q -> ff).
Now if we take the following identity (A -> (B -> C)) = (A & B -> C), we
see that the above is equivalent to:
P & Q -> ff.
There is now one problem, how can we ask negative queries? There is one
way to make use of minimal logic which is different from negation as
failure. The idea is that a query of the form:
G |- A -> B
is answered by temporarily adding A to the prolog program G, and then
trying to solve B, i.e. doing the following:
G, A |- B
Now lets turn to Prolog notation, we will show that p, and p -> ~q
implies ~q by executing a (minimal logic) Prolog program. The
prolog program is:
p.
ff :- p, q.
And the query is:
?- q -: ff.
We first need to define the new connective (-:)/2. A quick solution
is as follows:
(A -: B) :- (assert(A); retract(A), fail), B, (retract(A); assert(A), fail).
Here you see a realisation of this minimal logic negation in SWI Prolog:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 5.10.4)
Copyright (c) 1990-2011 University of Amsterdam, VU Amsterdam
1 ?- [user].
:- op(1200,xfy,-:).
|: (A -: B) :- (assertz(A); retract(A), fail), B, (retract(A); assertz(A), fail).
|: p.
|: ff :- p, q.
|:
% user://1 compiled 0.02 sec, 1,832 bytes
true.
2 ?- q -: ff.
true .
Best Regards
Reference:
Uniform Proofs as a Foundation for Logic Programming (1989)
by Dale Miller, Gopalan Nadathur, Frank Pfenning, Andre Scedrov