nicomp
nicomp

Reputation: 4647

Why do both predicates get evaluated?

I have this predicate with two clauses:

abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.

and I submit this to the interpreter:

?- abs(-5,W).
W = 5 ;
false.

?- 

Why does it evaluate the second clause and return false? Is there a way around that?

Upvotes: 1

Views: 83

Answers (1)

Peter Ludemann
Peter Ludemann

Reputation: 1005

You wrote two clauses that are disjoint on the 1st argument(X) and were surprised that Prolog backtracked into the 2nd one even though the first one was satisfied.

abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.

When the 1st clause was satisfied, the Prolog engine only knew that there was a 2nd clause that hadn't been evaluated; when you typed ";", it tried the 2nd clause, which failed. To see why, consider a slightly different (and not as good) version of your code:

abs2(X, Y) :- X =< 0, Y is - X.
abs2(X, Y) :- X >= 0, Y = X.

?- abs2(0, Y).
Y = 0 ;
Y = 0 ;

In this situation, even though the 1st clause succeeds, the 2nd clause can also succeed.

So, how to avoid this? It depends on what you want to accomplish. If you want to get all the answers, do something like this:

?- setof(W, abs(-5, W), Ws).
Ws = [5].

To print them all:

?- forall(abs(-5, W), format('W = ~q~n', [W])).
W = 5

If you want to tell the Prolog engine that your predicate is deterministic, you can use an if-then-else:

abs(X, Y) :-
    (   X < 0
    ->  Y is -X
    ;   Y = X
    ).

This can also be written with a cut("!"), but it's often easier to understand with if-then-else.

And, if you're using the latest version of SWI-Prolog, you can use the "=>" notation:

abs(X, Y), X < 0 => Y is -X.
abs(X, Y) => true.

Upvotes: 4

Related Questions