Отрицание в пролог-запросе не работает

Привет, у меня есть простая база данных знаний, определенная как:

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

Я пытаюсь написать правило, которое будет отвечать на запрос: Показать все классы автомобилей, которые работают на «масле» и НЕ ЯВЛЯЮТСЯ «большими».

Я пытаюсь реализовать это, используя:

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

но это не работает.


person kshitij singh    schedule 03.01.2016    source источник


Ответы (2)


Вы должны понимать разницу между предикатом и функтором.

Если мы немного упрощаем, предикат — это идентификатор на верхнем уровне, поэтому carClass/3 — это предикат, write/1 — это предикат, а onOilButNotBig/0 — это. Вы можете вызвать предикат. Предикат с заполненными аргументами является целью.

С другой стороны, функтор — это идентификатор не верхнего уровня. Константы — это функторы, переменные — это функторы, а функции с аргументами — это функторы. Примерами функторов являются 'X1', 'oil' и foo(X,bar,qux(2)).

Отрицание предполагает наличие цели. 'big' в данном случае не является целью, фактически \+('big') сам по себе является функтором.

Вы можете решить эту проблему, только превратив условие в цель и убедившись, что вы его вызовете. Это можно сделать так:

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

Кроме того, я действительно не понимаю, почему вы называете carClass/3 дважды. Эквивалентная и немного более эффективная программа выглядит следующим образом:

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

Наконец, как отмечено @Repeat, для предикатов и функций необходимо использовать имена, начинающиеся с нижнего регистра.

person Willem Van Onsem    schedule 03.01.2016

Перво-наперво!

  • Код не компилируется1. Почему? Имена предикатов обычно начинаются с символов нижнего регистра2.

    Мой совет: вместо OnOilButNotBig пишите onOilButNotBig!

  • Чтобы выразить неравенство терминов, используйте правый prolog-dif цели, например:

    onOilButNotBig :-
       dif(X, big),
       carClass(CarClass, oil, _),
       carClass(CarClass, oil, X),
       write(CarClass).
    
  • В качестве побочного замечания, есть еще несколько проблем с вашим кодом:

    1. Используйте ввод-вывод на основе побочных эффектов только при необходимости.

      В большинстве случаев предпочтительнее использовать интерактивный prolog-toplevel для ввода/вывода данных!

      onOilButNotBig(CarClass) :-
         dif(X, big),
         carClass(CarClass, oil, _),
         carClass(CarClass, oil, X).
      
    2. Для удобочитаемости не используйте такие атомы, как 'oil' и 'Oil'.

      Выберите один и придерживайтесь его! Я предлагаю oil (нижний регистр), который не нуждается в экранировании.

    3. Цель carClass(CarClass, oil, _) совершенно избыточна.

      Почему? Это обобщение близкой цели carClass(CarClass,oil,X).


Сноска 1: При использовании b-prolog 8.1, sicstus-prolog 4.3.2, swi-prolog 7.3.14 и