Related
Let's imagine a simple database of genealogy facts where mother(M, C) and father(F, C) denotes that M/F is the mother/father of child C.
I've written a rule to find known parents of a child (zero, one or both):
parents(C, M, F) :-
(mother(M, C) -> true; true),
(father(M, C) -> true; true).
which binds M and F if they are known and leaves them unbound otherwise.
It works fine, which means that for a set of facts:
mother(m1, c1).
father(f1, c1).
mother(m2, c2).
a call to parents(c1, M, F) returns:
M = m1,
F = f1.
while parents(c2, M, F) returns:
M = m2.
but the use of the arrow operators seems a little strange to me. Am I missing something basic? Can the (X -> true ; true) calls be avoided/simplified?
Any help appreciated.
Cheers,
From a logical perspective, a major mistake in this program is its incompleteness.
Consider for example the most general query:
?- parents(X, Y, C).
X = c1,
Y = m1.
So, no solution for c2 is reported.
But such a solution exists, as can be seen with:
?- parents(c2, Y, C).
Y = m2.
So, which is it, is there a solution or not?
Such mistakes almost invariably arise if you use (->)/2 and other constructs that violate logical purity of your code. Please see logical-purity for more information.
Hence, from a logical perspective, I can only recommend to avoid such constructs, since they defeat the primary advantage of a logic programming language to begin with: The ability to reason logically about your programs.
Instead, focus on a clear description of the relations you want to describe, and state the conditions that make them true. This will allow you to use your Prolog programs in a sensible way.
EDIT: I see you prefer a botched program. For this purpose, I recommend ignore/1. ignore(Goal) calls Goal as once(Goal), and succeeds. You can use this to simplify your program and still ensure that it remains incomplete.
Prolog is a real down to earth programming language. It has a pure subset. Both have their place.
once( (A ; true) ) is the answer to the question "how can we simplify (A -> true; true)".
If you want more purity, you could write (A *-> true ; true ) with the "soft cut" *-> which admits all solutions from the successful A and only switches to the unsuccessful branch in case A didn't produce any. See also e.g. this answer of mine for more discussion.
Another variant is (A ; \+ A).
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.
I am currently trying to learn some basic prolog. As I learn I want to stay away from if else statements to really understand the language. I am having trouble doing this though. I have a simple function that looks like this:
if a > b then 1
else if
a == b then c
else
-1;;
This is just very simple logic that I want to convert into prolog.
So here where I get very confused. I want to first check if a > b and if so output 1. Would I simply just do:
sample(A,B,C,O):-
A > B, 1,
A < B, -1,
0.
This is what I came up with. o being the output but I do not understand how to make the 1 the output. Any thoughts to help me better understand this?
After going at it some more I came up with this but it does not seem to be correct:
Greaterthan(A,B,1.0).
Lessthan(A,B,-1.0).
Equal(A,B,C).
Sample(A,B,C,What):-
Greaterthan(A,B,1.0),
Lessthan(A,B,-1.0),
Equal(A,B,C).
Am I headed down the correct track?
If you really want to try to understand the language, I recommend using CapelliC's first suggestion:
sample(A, B, _, 1) :- A > B.
sample(A, B, C, C) :- A == B.
sample(A, B, _, -1) :- A < B.
I disagree with CappeliC that you should use the if/then/else syntax, because that way (in my experience) it's easy to fall into the trap of translating the different constructs, ending up doing procedural programming in Prolog, without fully grokking the language itself.
TL;DR: Don't.
You are trying to translate constructs you know from other programming languages to Prolog. With the assumption that learning Prolog means essentially mapping one construct after the other into Prolog. After all, if all constructs have been mapped, you will be able to encode any program into Prolog.
However, by doing that you are missing the essence of Prolog altogether.
Prolog consists of a pure, monotonic core and some procedural adornments. If you want to understand what distinguishes Prolog so much from other programming languages you really should study its core first. And that means, you should ignore those other parts. You have only so much attention span, and if you waste your time with going through all of these non-monotonic, even procedural constructs, chances are that you will miss its essence.
So, why is a general if-then-else (as it has been proposed by several answers) such a problematic construct? There are several reasons:
In the general case, it breaks monotonicity. In pure monotonic Prolog programs, adding a new fact will increase the set of true statements you can derive from it. So everything that was true before adding the fact, will be true thereafter. It is this property which permits one to reason very effectively over programs. However, note that monotonicity means that you cannot model every situation you might want to model. Think of a predicate childless/1 that should succeed if a person does not have a child. And let's assume that childless(john). is true. Now, if you add a new fact about john being the parent of some child, it will no longer hold that childless(john) is true. So there are situations that inherently demand some non-monotonic constructs. But there are many situations that can be modeled in the monotonic part. Stick to those first.
if-then-else easily leads to hard-to-read nesting. Just look at your if-then-else-program and try to answer "When will the result be -1"? The answer is: "If neither a > b is true nor a == b is true". Lengthy, isn't it? So the people who will maintain, revise and debug your program will have to "pay".
From your example it is not clear what arguments you are considering, should you be happy with integers, consider to use library(clpfd) as it is available in SICStus, SWI, YAP:
sample(A,B,_,1) :- A #> B.
sample(A,B,C,C) :- A #= B.
sample(A,B,_,-1) :- A #< B.
This definition is now so general, you might even ask
When will -1 be returned?
?- sample(A,B,C,-1).
A = B, C = -1, B in inf..sup
; A#=<B+ -1.
So there are two possibilities.
Here are some addenda to CapelliC's helpful answer:
When starting out, it is sometimes easy to mistakenly conceive of Prolog predicates functionally. They are either not functions at all, or they are n-ary functions which only ever yield true or false as outputs. However, I often find it helpful to forget about functions and just think of predicates relationally. When we define a predicate p/n, we're describing a relation between n elements, and we've named the relation p.
In your case, it sounds like we're defining conditions on an ordered triplet, <A, B, C>, where the value of C depends upon the relation between A and B. There are three relevant relationships between A and B (here, since we are dealing with a simple case, these three are exhaustive for the kind of relationship in question), and we can simply describe what value C should have in the three cases.
sample(A, B, 1.0) :-
A > B.
sample(A, B, -1.0) :-
A < B.
sample(A, B, some_value) :-
A =:= B.
Notice that I have used the arithmetical operator =:=/2. This is more specific than ==/2, and it lets us compare mathematical expressions for numerical equality. ==/2 checks for equivalence of terms: a == a, 2 == 2, 5+7 == 5+7 are all true, because equivalent terms stand on the left and right of the operator. But 5+7 == 7+5, 5+7 == 12, A == a are all false, since it are the terms themselves which are being compared and, in the first case the values are reversed, in the second we're comparing +(5,7) with an integer and in the third we're comparing a free variable with an atom. The following, however, are true: 2 =:= 2, 5 + 7 =:= 12, 2 + 2 =:= 4 + 0. This will let us unify A and B with evaluable mathematical expressions, rather than just integers or floats. We can then pose queries such as
?- sample(2^3, 2+2+2, X).
X = 1.0
?- sample(2*3, 2+2+2, X).
X = some_value.
CapelliC points out that when we write multiple clauses for a predicate, we are expressing a disjunction. He is also careful to note that this particular example works as a plain disjunction only because the alternatives are by nature mutually exclusive. He shows how to get the same exclusivity entailed by the structure of your first "if ... then ... else if ... else ..." by intervening in the resolution procedure with cuts. In fact, if you consult the swi-prolog docs for the conditional ->/2, you'll see the semantics of ->/2 explained with cuts, !, and disjunctions, ;.
I come down midway between CapelliC and SQB in prescribing use of the control predicates. I think you are wise to stick with defining such things with separate clauses while you are still learning the basics of the syntax. However, ->/2 is just another predicate with some syntax sugar, so you oughtn't be afraid of it. Once you start thinking relationally instead of functionally or imperatively, you might find that ->/2 is a very nice tool for giving concise expression to patterns of relation. I would format my clause using the control predicates thus:
sample(A, B, Out) :-
( A > B -> Out = 1.0
; A =:= B -> Out = some_value
; Out = -1.0
).
Your code has both syntactic and semantic issues.
Predicates starts lower case, and the comma represent a conjunction. That is, you could read your clause as
sample(A,B,C,What) if
greaterthan(A,B,1.0) and lessthan(A,B,-1.0) and equal(A,B,C).
then note that the What argument is useless, since it doesn't get a value - it's called a singleton.
A possible way of writing disjunction (i.e. OR)
sample(A,B,_,1) :- A > B.
sample(A,B,C,C) :- A == B.
sample(A,B,_,-1) :- A < B.
Note the test A < B to guard the assignment of value -1. That's necessary because Prolog will execute all clause if required. The basic construct to force Prolog to avoid some computation we know should not be done it's the cut:
sample(A,B,_,1) :- A > B, !.
sample(A,B,C,C) :- A == B, !.
sample(A,B,_,-1).
Anyway, I think you should use the if/then/else syntax, even while learning.
sample(A,B,C,W) :- A > B -> W = 1 ; A == B -> W = C ; W = -1.
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
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(_).