kshitij singh
kshitij singh

Reputation: 363

Negation in prolog query is not working

HI i have a simple knowledge database defined as:

carClass('X1','Oil','small').
carClass('X2','gas','big').
carClass('X3','Petrol','big').
carClass('X4','oil','small').
carClass('X5','Oil','small').
carClass('X6','gas','big').

I am trying to write a rule that will answer the query: Display all carClass that runs on 'oil' and IS NOT 'big'.

I am trying to implement it using:

OnOilButNotBig :-
   carClass(CarClass,'oil',_),
   carClass(CarClass,'oil', \+('big') ),
   write(CarClass).

but this is not working.

Upvotes: 1

Views: 1014

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477607

You have to understand the difference between a predicate and a functor.

If we oversimplify things a bit, a predicate is an identifier at the top level, so carClass/3 is a predicate, write/1 is a predicate and onOilButNotBig/0 is. You can call a predicate. A predicate with filled in arguments is a goal.

A functor on the other hand is an identifier not on the top level. Constants are functors, variables are functors, and functions with arguments are functors. Examples of functors are 'X1', 'oil' and foo(X,bar,qux(2)).

The negation expects a goal. 'big' in this case is not a goal, in fact \+('big') itself is a functor.

You can only solve this by turning the condition into a goal and ensure you will call it. This can be done like:

onOilButNotBig :-
   carClass(CarClass,'oil',_),
   carClass(CarClass,'oil',X),
   \+(X = 'big'),
   write(CarClass).

Furthermore I do not really see why you call carClass/3 twice. An equivalent and slightly more efficient program is the following:

onOilButNotBig :-
   carClass(CarClass,'oil',X),
   \+(X = 'big'),
   write(CarClass).

Finally as @Repeat noted, you need to use names that start with a lowercase for predicates and functions.

Upvotes: 2

repeat
repeat

Reputation: 18726

First things first!

  • The code doesn't compile1. Why? Predicate names usually start with lowercase characters2.

    My advice: instead of OnOilButNotBig write onOilButNotBig!

  • To express term inequality, use the right goal(s), like so:

    onOilButNotBig :-
       dif(X, big),
       carClass(CarClass, oil, _),
       carClass(CarClass, oil, X),
       write(CarClass).
    
  • As a side remark, there are a few more issues with your code:

    1. Use side-effect based I/O only when necessary.

      In most cases, it is preferable to use the interactive for data input/output!

      onOilButNotBig(CarClass) :-
         dif(X, big),
         carClass(CarClass, oil, _),
         carClass(CarClass, oil, X).
      
    2. For the sake of readability, please do not use atoms like 'oil' and 'Oil'.

      Pick one and stick to it! I suggest oil (lowercase) which does not need escaping.

    3. The goal carClass(CarClass, oil, _) is completely redundant.

      Why? It is a generalisation of the close-by goal carClass(CarClass,oil,X).


Footnote 1: When using 8.1, 4.3.2, 7.3.14, and 3.6.
Footnote 2: Names can also starting with uppercase characters if the right (escaping with single-quotes) is utilized.
Footnote 3: In general, redundant goals are ok, but they suggest to me your code will likely not behave as intended.

Upvotes: 1

Related Questions