Шаг 32.
Основы логического программирования.
Детерминизм и отсечение

    На этом шаге мы рассмотрим детерминизм и отсечение.

    Если бы предикат friend, определенный в предыдущей программе, не содержал отсечений, то это был бы недетерминированный предикат (способный производить множественные решения при помощи поиска с возвратом). В предыдущих реализациях Пролога программисты должны были обращать особое внимание на недетерминированные предложения из-за сопутствующих им дополнительных требований к ресурсам памяти. Теперь Пролог сам выполняет проверку на недетерминированные предложения, облегчая вашу работу.

    В Прологе существует директива компилятора check_determ. Если вставить эту директиву в самое начало программы, то Пролог будет выдавать предупреждение в случае обнаружения недетерминированных предложений в процессе компиляции.

    Вы можете превратить недетерминированные предложения в детерминированные, вставляя отсечения в тело правил, определяющих данный предикат. Например, помещение отсечений в предложения, определяющие предикат friend, делает этот предикат детерминированным, поскольку в данном случае обращение к friend может возвратить одно и только одно решение.

Предикат not

    Следующая программа pro32_1.pro демонстрирует, как вы можете использовать предикат not для того, чтобы выявить успевающего студента: студента, у которого средний балл (GPA) не менее 3.5 и у которого в настоящее время не продолжается испытательный срок.

   domains
      name=symbol 
      gpa = real
   predicates
      honor_student(name) 
      student(name,gpa) 
      probation(name)
   clauses
      honor_student(Name):-
         student(Name,GPA), 
         GPA>=3.5, 
         not(probation(Name)).
      student("Betty Blue",3.5).
      student("David Smith",2.0).
      student("John Johnson",3.7).
      probation("Betty Blue"),
      probation("David Smith").
   goal
       honor_student (X).
Текст этой программы можно взять здесь.


    Замечание. При использовании предиката not необходимо иметь в виду следующее: предикат not будет успешным, если не может быть доказана истинность данной подцели.

    Этo приводит к предотвращению связывания внутри not несвязанных переменных. При вызове изнутри not подцели со свободными переменными, Пролог возвратит сообщение об ошибке: "Free variables not allowed in not or retractall" (Свободные переменные не разрешены в not или retract). Это происходит вследствие того, что для связывания свободных переменных в подцели, подцель должна унифицироваться с каким-либо другим предложением и выполняться. Правильным способом управления несвязанными переменными подцели внутри not является использование анонимных переменных.


    Вот несколько примеров корректных и некорректных предложений:
   likes(bill,Anyone):-	% Anyone - выходной аргумент 
      likes(sue,Anyone), 
      not(hates(bill,Anyone).

    В этом примере Anyone связывается посредством likes(sue,Anyone) до того, как Пролог делает вывод, что hates (bill, Anyone) не является истиной. Данное предложение работает корректно.

    Если вы измените его таким образом, что обращение к not будет выполняться первым, то получите сообщение об ошибке: "Free variable are not allowed in not" (Свободные переменные в not не разрешены).

   likes(bill,Anyone):- %  Это не будет работать  правильно 
      not(hates(bill,Anyone)),
      likes(sue,Anyone).

    Даже если вы замените в not(hates (bill, Anyone)) Anyone на анонимную переменяю, и предложение, таким образом, не будет возвращать ошибку, все равно получите неправильный результат.

   likes(bill,Anyone):- %  Это не будет работать  правильно 
      not(hates(bill,_)),
      likes(sue,Anyone).

    Это предложение утверждает, что Биллу нравится кто угодно, если неизвестно ничего о том, кого Билл ненавидит, и если этот "кто-то" правится Сью. Подлинное предложение утверждало, что Биллу нравится тот, кто нравится Сью, и при этом Билл не испытывает к этому человеку ненависти.

    Неверное использование предиката not приведет к сообщению об ошибке или к ошибкам в логике вашей программы. Следующая программа pro32_2.pro является примером правильного использования предиката not.

   predicates
      likes_shopping(symbol) 
      has_credit_card (symbol, symbol)
      bottomed_out(symbol,symbol)
   clauses
      likes_shopping(Who):-
         has_credit_card(Who,Card),
         not(bottomed_out(Who, Card)),
         write(Who," can shop with the ",Card, " credit card.\n").
      has_credit_card(chris,visa).
      has_credit_card(chris,diners).
      has_credit_card(joe,shell). 
      has_credit_card(sam,mastercard).
      has_credit_card(sam,citibank).
      bottomed_out(chris,diners).
      bottomed_out(sam,mastercard).
      bottomed_out(chris, visa) .
   goal
      likes_shopping(Who).
 
Текст этой программы можно взять здесь.

    Со следующего шага мы начнем рассматривать факты и правила в качестве процедур.




Предыдущий шаг Содержание Следующий шаг