In Prolog, how do you implement compound logical predicates like (A and B) or (C and D)?
This may seem like a simple question but many approachable online tutorials are not detailed enough on boolean expressions. I assume you can't just write:
test(A, B, C, D) :- cond(A), cond(B); cond(C), cond(D).
so how would you do it?
As noted by others, your original example
test(A, B, C, D) :- cond(A), cond(B); cond(C), cond(D).
is perfectly valid (assuming the parse is as you intended it). Didn't you try it?
A Primer
Logical AND
foo :- a , b .
Logical OR
foo :- a ; b .
Combined
foo :- a , b ; c , d .
The above parses as:
foo :- ( a , b ) ; ( c , d ) .
Use parentheses to indicate a different desired binding:
foo :- a , ( b ; c ) , d .
Even better, eschew the ;
OR operator and break alternatives up into separate clauses. Sequence is much easier for people to comprehend than branching tree structures. Breaking alternation up into multiple clauses simplifies testing/debugging and improves comprehension. Therefore, prefer
foo :- a , b .
foo :- c , d .
over
foo :- a , b ; c , d .
and prefer
foo :- a , bar , d .
bar :- b .
bar :- c .
over
foo :- a , ( b ; c ) , d .
Possibly most importantly, breaking things up into multiple clauses like this makes later maintenance easier. With a structure like:
foo :- a , b ; c , d .
what do you do when you add another case? What about when it expands to 50 alternatives?
Each additional alternative increases the number of code paths through the clause, thus making testing and comprehension more difficult. To get complete code coverage in testing, a lot of alternative paths must be individually tested.
With the equivalent structure
foo :- a , b .
foo :- c , d .
Adding alternatives is simply a matter of adding additional clause or clauses, each of which can be tested in isolation.
A professional programmer writes first for the people who will, several years down the line, need to comprehend, change and fix that code (hint: that person might be yourself).
A simple alternative for conjunctions is to use substatements. For disjunctions, use multiple lines. Your example:
test(A, B, C, D) :- test1(A, B).
test(A, B, C, D) :- test2(C, D).
test1(A, B) :- A, B.
test2(C, D) :- C, D.
What about (A or B) and (C or D)?
other(A, B, C, D) :- other1(A, B), other2(C, D).
other1(A, B) :- A.
other1(A, B) :- B.
other2(C, D) :- C.
other2(C, D) :- D.
Note that this is only mentioned as an alternative to joel76's answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With