In SWI Prolog:
Exact clause duplicates are allowed:
a(1).
a(1).
?- a(X).
X = 1 ;
X = 1.
or even:
c :- format("Hello from first c!").
c :- format("Hello from second c!").
Hello from first c!
true ;
Hello from second c!
true.
More generally, so are clauses with identical fully ground heads but differing bodies:
b(1) :- format("Hello from first b!").
b(1) :- format("Hello from second b!").
?- b(1).
Hello from first b!
true ;
Hello from second b!
true.
Clauses with identical non-ground head feel somewhat more reasonable:
p(X) :- format("Yup, this is p(~w)",X).
p(X) :- format("Yup, this is also p(~w)",X).
p(X) :- format("You think you can get rid of good old p(~w) just like that?",X).
?- p('homer simpson').
Yup, this is p(homer simpson)
true ;
Yup, this is also p(homer simpson)
true ;
You think you can get rid of good old p(homer simpson) just like that?
true.
?- p(X).
Yup, this is p(_4782)
true ;
Yup, this is also p(_4782)
true ;
You think you can get rid of good old p(_4782) just like that?
true.
This covers the reasonable case of clauses with a guarded body:
p(X) :- X < 0, format("It's less than 0: ~w", X).
p(X) :- X =:= 0, format("It's exactly 0: ~w", X).
p(X) :- X > 0, format("It's larger than 0: ~w", X).
On second thoughts ... we already encounter the ultimate case in the built-in repeat
:
?- repeat.
true ;
true ;
true ;
true ;
…
Or can construct an intermediate case easily:
h :- member(_,[1,2,3]).
?- h.
true ;
true ;
true.
Somehow textbooks gloss over the fact that predicates have additional semantics: they can not only be false
or true
for any given ground arguments, but they can actually be true(n)
- "true n times, n ≥ 0" .
From a theory standpoint, this is dubious, at least for vanilla classical logic.
On the other hand, it is useful from a computational standpoint for:
- Side-effects (rather for output than for input, and rather marginally).
- Control of the computation (i.e.
repeat
).
Are there any other uses?
I really feel the compiler should flag variable-less cases like a/1
, c/0
, b/1
above as errors (easy to detect), and even repeat/0
should probably have a value: repeat(Count)
. Anything which redoes successfully should NOT redo successfully in the same context on exactly the same ground arguments. It has the same squishy feeling of irrelevancy as a(X) :- b(Y). b(Z).
Brrr!.