Программирование на языке пролог
Шрифт:
предложение(Х):-присоединить(Y,Z,Х), группа_существительного(Y), группа_глагола(Z).
Аналогично
группа_существительного(Х):- присоединить(Y,Z,Х), определитель(Y), существительное(Z).
группа_глагола(Х):- присоединить(Y,Z,Х), глагол(Y), группа_существительного(Z).
группа_глагола(Х):- глагол(Х).
Отметим, что два правила для предиката группа_ глаголапревращаются в два утверждения для нашего предиката, что соответствует двум возможным способам проверки последовательности на принадлежность классу группа_глагола.
определитель([the]).
существительное([аррlе]).
существительное([man]).
глагол([eats]).
глагол([sings]).
Теперь наша программа завершена. Действительно, эта программа успешно идентифицирует последовательности слов, являющиеся предложениями для приведенной грамматики. Однако, прежде чем считать задачу решенной, следует посмотреть, что в действительности произойдет, когда мы зададим вопрос о некоторой последовательности слов. Рассмотрим утверждение для предиката предложение:
предложение(Х):- присоединить(Y,Z,Х), группа_существительного(Y), группа_глагола(Z).
и следующий вопрос:
?- предложение([the, man, eats, the, apple]).
Переменная Xв правиле конкретизируется значением [the, man, eats, the, apple], а переменные Yи Zне будут конкретизированы, так что данная цель будет порождать возможные пары значений для Yи Zтакие, что результат присоединения списка Zк списку Yравен X. С помощью механизма возврата будут порождены все возможные пары, по одной при каждом возврате. Цель группа_ существительногобудет выполняться лишь при условии, что Yдействительно приемлем как группа_существительного. Иначе она не выполняется и присоединить будет вынужден найти другое значение для Y. Так что последовательность выполнения первой части предиката предложениебудет следующей:
1. Целью является предложение(thе, man, eats, the, apple]).
2. Разбиение исходного списка на два списка Yи Z. Возможны следующие варианты разбиения;
Y = [], Z = [the,man,eats,the,apple] Y = [the], Z = [man,eats,the,apple]
Y= [the,man], Z = [eats,the,apple]
Y= [the,man,eats], Z = [the,apple]
Y= [the,man,eats,the], Z = [apple]
Y= [the, man, eats, the, apple], Z = []
3. Выбор варианта значений для Yи Zиз приведенного выше списка вариантов и проверка принадлежности Yклассу группа_существительного.То есть, попытка согласования подцели группа_существительного(Y).
4. Если группа_существительноговыполняется для Y, то перейти к группа_глагола.Иначе возвратиться к шагу 3 и попробовать другой вариант.
Очевидно, что при таком подходе выполняется совершенно ненужный поиск. Цель присоединить(Y,Z,X)порождает множество решений, большая часть которых бесполезна и не может быть идентифицирована как группа существительного. Должен существовать более прямой путь получения решения. Как следует из нашей грамматики, группа_существительногодолжна содержать в точности два слова. Этим можно было бы воспользоваться, чтобы не прибегать к поиску среди возможных вариантов разбиения исходной последовательности слов. Опасность заключается в том, что это не всегда так, если мы изменяем грамматику.
Таким образом, эвристика относительно длины группы существительного имеет слишком частный характер, чтобы ее использовать в программе. Тем не менее, ее можно рассматривать как частный случай некоторого общего принципа. Если мы хотим выделить подпоследовательность, которая является группой существительного, то мы можем использовать свойства этой группы, чтобы ограничить набор подходящих для этого последовательностей. Если определение группы существительного подвержено изменениям, то это можно сделать, только передав всю ответственность по проверке соответствующих свойств утверждению группа_существительного.Так как именно утверждение группа_ существительноговыражает свойства, которыми обладает группа существительного, то почему не предположить, что этот предикат сам может решить, на что должна быть похожа соответствующая последовательность? Давайте потребуем, чтобы предикат группа_существительногосам решил, какая часть последовательности ему необходима и что необходимо оставить для последующей обработки предикатом группа_глагола.
Это обсуждение приводит нас к новому определению предиката группа_существительного,который теперь имеет уже два аргумента:
группа_существительного(Х, Y) истинно, если начальная часть последовательности X является группой существительного, а остальная часть последовательности есть Y.
Таким образом, можно было бы ожидать, что следующие вопросы:
?- группа_существительного([the,man,eats,the,apple], [eats, the,apple]).
?- группа_существительного([thе,аррlе,sings], [sings]).
должны иметь ответ «да». Теперь, чтобы отразить это изменение, мы должны пересмотреть определение предиката группа_существительного.Для этого надо решить, как последовательность, выбранная в качестве группы существительного, разбивается на последовательность, представляющую определитель, за которой следует последовательность, являющаяся существительным. Мы можем вновь предоставить решение задачи о том, какую часть последовательности следует выбрать, непосредственно тем утверждениям, которые обрабатывают соответствующие группы слов, положив:
группа_существительного(Х,Y):- определитель(Х,Z), существительное(Z, Y).
Таким образом, в начале последовательности Xимеется группа, существительного,если мы можем выделить определитель в начале X, обозначив оставшуюся часть Z, а затем можем выделить существительное в начале Z. Часть последовательности, остающаяся после выделения группы существительного, совпадает с последовательностью, следующей за существительным. На диаграмме это выглядит так:
[the, man, eats, the, apple]
|--------------X--------------|
|-----------Z-----------|
|-------Y-------|
Для того чтобы все происходило так, как здесь описано, мы должны будем принять относительно предикатов определительи существительноесоглашение, подобное тому, какое мы приняли для предиката группа_существительного.