'if' in prolog?

Is there a way to do an if in prolog, e.g. if a variable is 0, then to do some actions (write text to the terminal). An else isn't even needed, but I can't find any documentation of if.

2

10 Answers

Yes, there is such a control construct in ISO Prolog, called ->. You use it like this:

( condition -> then_clause ; else_clause ) 

Here is an example that uses a chain of else-if-clauses:

( X < 0 -> writeln('X is negative. That's weird! Failing now.'), fail ; X =:= 0 -> writeln('X is zero.') ; writeln('X is positive.') ) 

Note that if you omit the else-clause, the condition failing will mean that the whole if-statement will fail. Therefore, I recommend always including the else-clause (even if it is just true).

1

A standard prolog predicate will do this.

 isfive(5). 

will evaluate to true if you call it with 5 and fail(return false) if you run it with anything else. For not equal you use \=

isNotEqual(A,B):- A\=B. 

Technically it is does not unify, but it is similar to not equal.

Learn Prolog Now is a good website for learning prolog.

Edit: To add another example.

isEqual(A,A). 
1

Prolog predicates 'unify' -

So, in an imperative langauge I'd write

function bazoo(integer foo) { if(foo == 5) doSomething(); else doSomeOtherThing(); } 

In Prolog I'd write

bazoo(5) :- doSomething. bazoo(Foo) :- Foo =/= 5, doSomeOtherThing. 

which, when you understand both styles, is actually a lot clearer.
"I'm bazoo for the special case when foo is 5"
"I'm bazoo for the normal case when foo isn't 5"

4

First, let's recall some classical first order logic:

"If P then Q else R" is equivalent to "(P and Q) or (non_P and R)".


How can we express "if-then-else" like that in Prolog?

Let's take the following concrete example:

If X is a member of list [1,2] then X equals 2 else X equals 4.

We can match above pattern ("If P then Q else R") if ...

  • condition P is list_member([1,2],X),
  • negated condition non_P is non_member([1,2],X),
  • consequence Q is X=2, and
  • alternative R is X=4.

To express list (non-)membership in a pure way, we define:

 list_memberd([E|Es],X) :- ( E = X ; dif(E,X), list_memberd(Es,X) ). non_member(Es,X) :- maplist(dif(X),Es). 

Let's check out different ways of expressing "if-then-else" in Prolog!

  1. (P,Q ; non_P,R)

     ?- (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4). X = 2 ; X = 4. ?- X=2, (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=2. X = 2 ; false. ?- (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=2. X = 2 ; false. ?- X=4, (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=4. X = 4. ?- (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=4. X = 4. 

    Correctness score 5/5. Efficiency score 3/5.

  2. (P -> Q ; R)

     ?- (list_memberd([1,2],X) -> X=2 ; X=4). false. % WRONG ?- X=2, (list_memberd([1,2],X) -> X=2 ; X=4), X=2. X = 2. ?- (list_memberd([1,2],X) -> X=2 ; X=4), X=2. false. % WRONG ?- X=4, (list_memberd([1,2],X) -> X=2 ; X=4), X=4. X = 4. ?- (list_memberd([1,2],X) -> X=2 ; X=4), X=4. false. % WRONG 

    Correctness score 2/5. Efficiency score 2/5.

  3. (P *-> Q ; R)

     ?- (list_memberd([1,2],X) *-> X=2 ; X=4). X = 2 ; false. % WRONG ?- X=2, (list_memberd([1,2],X) *-> X=2 ; X=4), X=2. X = 2 ; false. ?- (list_memberd([1,2],X) *-> X=2 ; X=4), X=2. X = 2 ; false. ?- X=4, (list_memberd([1,2],X) *-> X=2 ; X=4), X=4. X = 4. ?- (list_memberd([1,2],X) *-> X=2 ; X=4), X=4. false. % WRONG 

    Correctness score 3/5. Efficiency score 1/5.


(Preliminary) summary:

  1. (P,Q ; non_P,R) is correct, but needs a discrete implementation of non_P.

  2. (P -> Q ; R) loses declarative semantics when instantiation is insufficient.

  3. (P *-> Q ; R) is "less" incomplete than (P -> Q ; R), but still has similar woes.


Luckily for us, there are alternatives: Enter the logically monotone control construct if_/3!

We can use if_/3 together with the reified list-membership predicate memberd_t/3 like so:

 ?- if_(memberd_t(X,[1,2]), X=2, X=4). X = 2 ; X = 4. ?- X=2, if_(memberd_t(X,[1,2]), X=2, X=4), X=2. X = 2. ?- if_(memberd_t(X,[1,2]), X=2, X=4), X=2. X = 2 ; false. ?- X=4, if_(memberd_t(X,[1,2]), X=2, X=4), X=4. X = 4. ?- if_(memberd_t(X,[1,2]), X=2, X=4), X=4. X = 4. 

Correctness score 5/5. Efficiency score 4/5.

0

I found this helpful for using an if statement in a rule.

max(X,Y,Z) :- ( X =< Y -> Z = Y ; Z = X ). 

Thanks to

There are essentially three different ways how to express something like if-then-else in Prolog. To compare them consider char_class/2. For a and b the class should be ab and other for all other terms. One could write this clumsily like so:

char_class(a, ab). char_class(b, ab). char_class(X, other) :- dif(X, a), dif(X, b). ?- char_class(Ch, Class). Ch = a, Class = ab ; Ch = b, Class = ab ; Class = other, dif(Ch, a), dif(Ch, b). 

To write things more compactly, an if-then-else construct is needed. Prolog has a built-in one:

?- ( ( Ch = a ; Ch = b ) -> Class = ab ; Class = other ). Ch = a, Class = ab. 

While this answer is sound, it is incomplete. Just the first answer from ( Ch = a ; Ch = b ) is given. The other answers are chopped away. Not very relational, indeed.

A better construct, often called a "soft cut" (don't believe the name, a cut is a cut is a cut), gives slightly better results (this is in YAP):

?- ( ( Ch = a ; Ch = b ) *-> Class = ab ; Class = other ). Ch = a, Class = ab ; Ch = b, Class = ab. 

Alternatively, SICStus has if/3 with very similar semantics:

?- if( ( Ch = a ; Ch = b ), Class = ab , Class = other ). Ch = a, Class = ab ; Ch = b, Class = ab. 

So the last answer is still suppressed. Now enter library(reif) for SICStus, YAP, and SWI. Install it and say:

?- use_module(library(reif)). ?- if_( ( Ch = a ; Ch = b ), Class = ab , Class = other ). Ch = a, Class = ab ; Ch = b, Class = ab ; Class = other, dif(Ch, a), dif(Ch, b). 

Note that all the if_/3 is compiled away to a wildly nested if-then-else for

char_class(Ch, Class) :- if_( ( Ch = a ; Ch = b ), Class = ab , Class = other ). 

which expands in YAP 6.3.4 to:

char_class(A,B) :- ( A\=a -> ( A\=b -> B=other ; ( A==b -> B=ab ) ; A=b, B=ab ; dif(A,b), B=other ) ; ( A==a -> B=ab ) ; A=a, B=ab ; dif(A,a), ( A\=b -> B=other ; ( A==b -> B=ab ) ; A=b, B=ab ; dif(A,b), B=other ) ). 

The best thing to do is to use the so-called cuts, which has the symbol !.

if_then_else(Condition, Action1, Action2) :- Condition, !, Action1. if_then_else(Condition, Action1, Action2) :- Action2. 

The above is the basic structure of a condition function.

To exemplify, here's the max function:

max(X,Y,X):-X>Y,!. max(X,Y,Y):-Y=<X. 

I suggest reading more documentation on cuts, but in general they are like breakpoints. Ex.: In case the first max function returns a true value, the second function is not verified.

PS: I'm fairly new to Prolog, but this is what I've found out.

2

Prolog program actually is big condition for "if" with "then" which prints "Goal is reached" and "else" which prints "No sloutions was found". A, Bmeans "A is true and B is true", most of prolog systems will not try to satisfy "B" if "A" is not reachable (i.e. X=3, write('X is 3'),nl will print 'X is 3' when X=3, and will do nothing if X=2).

( A == B -> writeln("ok") ; writeln("nok") ), 

The else part is required

1

You should read Learn Prolog Now! Chapter 10.2 Using Cut. This provides an example:

max(X,Y,Z) :- X =< Y,!, Y = Z.

to be said,

Z is equal to Y IF ! is true (which it always is) AND X is <= Y.

You Might Also Like