Reputation: 1088
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,
Upvotes: 3
Views: 170
Reputation: 40768
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.
Upvotes: 4
Reputation: 71065
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)
.
Upvotes: 1