Классификация с разбивкой по категориям
Предположим, что рассматривается база данных результатов встреч по теннису, в которых участвовали члены некоторого клуба. Пары соревнующихся игроков не были упорядочены с помощью какого-либо систематического способа (как при проведении турнира), поэтому база данных содержит информацию лишь о том, чем закончились встречи каждого игрока с некоторыми другими игроками. Эти результаты введены в программу после их представления в виде фактов примерно таким образом:
beat ( torn, jim! . beat( arm, torn). beat! pat, jim).
Необходимо определить отношение
class!. Player, Category)
которое позволяет разбить игроков на категории. Предусмотрены только три категории, описанные ниже.
Глава 5. Управление перебором с возвратами 127
• winner. Победителем является каждый игрок, который победил во всех поединках.
• fighter. Боец — это любой игрок, который выиграл в некоторых встречах, а а некоторых проиграл.
• sportsman. Звание спортсмен а-любителя присваивается тому игроку, который уступил во всех поединках.
Например, если доступны лишь приведенные выше результаты, то Энн и Пэт — победители, Том - боец, а Джим - спортсмен. Правило определения бойца можно легко сформулировать следующим образом:
X является бойцом, если
есть некоторый Y, такой, что X побеждает Y, и есть некоторый 2, такой, что Z побеждает X
Теперь сформулируем правило определения победителя:
X является победителем, если X побелил некоторого Y и X не был побежден никем.
Последняя формулировка содержит отрицание "не", которое нельзя непосредственно представить с помощью средств Prolog, рассматриваемых до сих пор. Поэтому формулировка отношения winner на первый взгляд кажется немного сложнее. Такая же проблема возникает при анализе отношения sportsman. Эту проблему можно обойти, объединив определение отношения winner с определением отношения fighter и воспользовавшись выражением "в противном случае". Такая формулировка приведена ниже.
Если X кого-то победил и X Был кем-то побежден, то X - боец,
в противном случае, если X кого-то победил, то X - победитель, в противном случае, если х был кем-то побежден,
то |
противном случа
Эту формулировку можно сразу же перевести на язык Prolog. Взаимное исключение трех альтернативных категорий обозначается операторами отсечения следующим образом:
beat ( _, X), I .
class (x,winner) :-beatt x, _ ) , ! .
class (X, sportsman):-
beatt _, x) .
Обратите внимание на то, что оператор отсечения в предложении для категории sportsman не требуется. При использовании подобных процедур с операторами отсечения необходимо соблюдать осторожность. Ниже показано, что при этом может произойти в ином случае.
?- class! ton. С).
С - fighter; I Как и следовало ожидать
по
?-class! torn, sportsman),
yes % Вогреки ожиданиям
Вызов отношения class является безопасным, если второй параметр не конкретизирован. В противном случае могут быть получены непредсказуемые результаты.
128 Часть I. Язык Prolog
Упражнения
5.1. Рассмотрим следующую программу:
Р(И .
Р(2) :- ! . Р(3) .
Напишите все ответы системы Prolog на приведенные ниже вопросы.
а) ?- р(Х) .
б) ?-р( X),р( Y) .
в) ?- р( х; ,!, р( Y).
5.2. Приведенное ниже отношение классифицирует числа на три категории: поло-
жительные, нуль и отрицательные.
class ( Number, positive) :- Number > 0.
class! 0, zero) .
class ( Number, negative) :- Number < 0.
Определите эту процедуру более эффективным способом с использованием оператора отсечения.
5.3. Определите процедуру
splits Numbers, Positives, Negatives)
которая разбивает список чисел на два списка; положительные (включая нуль)
и отрицательные, например, как показано ниже.
split ( [3,-1,0,5,-2], [3,0,5;, -1,-23)
Предложите две версии: одну с оператором отсечения, а другую без него.