2

I'm trying out an exercise where I have to write the predicate, colors/2 (or colors(C1,C2) :- ...) that runs like the following:

?- colors(red,blue).
true.
?- colors(red,red).
false.
?- colors(blue,blue).
false.

So, essentially, I have to write my predicate in a manner where it doesn't accept when you enter the same color twice.

I am defining my facts to be:

col(red,blue).
col(purple,orange).
col(green, yellow). 

I am making my predicate to be:

colors(X,Y) :- (col(X,Y); col(Y,X)) not (col(X,X); col(Y,Y)).

I don't understand why my predicate won't work. It is returning a syntax error with "Operator Expected." I am saying that it doesn't matter in what order you write the facts. Meaning, you can say colors(red,blue) or colors(blue,red), but you can't query colors with the same name without it returning false.

I would like to know:

  1. Why this isn't a valid expression.
  2. What I can do to fix the problem.
Jubl
  • 247
  • 3
  • 14
  • 2
    You're missing a comma `,` before `not` and `not/1` expects a single term, so use more parentheses: `colors(X,Y) :- (col(X,Y); col(Y,X)), not( (col(X,X); col(Y,Y)) ).` And better is `\+` than `not(_)`, so `colors(X,Y) :- (col(X,Y); col(Y,X)), \+ (col(X,X); col(Y,Y)).` You know that `col(X,X)` and `col(Y,Y)` will each always be false, right? Because there are no facts or predicates where `col(X,X)` is true where both arguments are the same. So `not( (col(X,X); col(Y,Y)) )` will always be `true`. – lurker Jan 28 '15 at 02:09
  • 1
    You're missing a comma before `not`. But `not/1` is deprecated. The standard operator for negation-as-failure is `\+/1`. – Paulo Moura Jan 28 '15 at 02:09
  • @lurker Thank you! If you post that as an answer, I'd gladly make it the top answer. I can't believe I overlooked that. I nearly tore my hair out! – Jubl Jan 28 '15 at 02:12
  • Sometimes it's just a "can't see the forest for the trees" problem. :) – lurker Jan 28 '15 at 02:16

1 Answers1

2

A couple of things:

You're missing a comma (,) before not and not/1 expects a single term in parentheses, so use more parentheses:

colors(X,Y) :- (col(X,Y); col(Y,X)), not( (col(X,X); col(Y,Y)) ).

As @PauloMora indicated, not/1 is deprecated in favor of the ISO \+/1, so better would be:

colors(X,Y) :- (col(X,Y); col(Y,X)), \+ (col(X,X); col(Y,Y)).

Then looking at col(X,X) and col(Y,Y), there are no facts or predicates where col(X,X) would be true (both arguments are the same). So each of these will always be false, and \+ (col(X,X); col(Y,Y)) will always be true. So the expression is superfluous, and your predicate becomes (at least with the pattern established in your current set of facts):

colors(X,Y) :- col(X,Y) ; col(Y,X).

Since you don't have any facts stipulated with matching colors (col(x,x)), then queries like col(red, red) will fail anyway.


Per the recommendation by @false, for an integrity check on equality of X and Y, the appropriate mechanism would be dif(X, Y):
colors(X, Y) :- (col(X, Y) ; col(Y, X)), dif(X, Y).

The parentheses are desired since , has higher precedence than ;. This would guard against the case where you happened to have a fact or predicate col/2 in which both arguments were the same (identical or unified).

lurker
  • 56,987
  • 9
  • 69
  • 103
  • Cool. I actually noticed that when I added in an extra fact like, col(red,blue) and then col(yellow,blue), it'd give me false in my original expression so this helped me a lot. – Jubl Jan 28 '15 at 02:20
  • I don't get it... why is there no `dif(X,Y)`? – false Jan 28 '15 at 13:21
  • @false, given the OP's current data set, isn't is superfluous (which is what I meant by the comment in my answer, *at least with the pattern established in your current set of facts*)? – lurker Jan 28 '15 at 13:28
  • I'd rather guess that OP wanted (= purpose of the exercise) either some integrity check or, well something with "compatibility of colors" or the like. – false Jan 28 '15 at 13:38
  • @false, I see what you mean. Good suggestion. – lurker Jan 28 '15 at 13:55