Давайте рассмотрим Пролог как кандидата на место языка логического программирования и посмотрим, насколько хорошо он для этого подходит. Прежде всего, ясно, что некоторые программы на Прологе действительно представляют описание проблемной области на языке логики. Запись:
мать(Х,Y):- родитель(Х,Y), женщина(Y).
можно рассматривать как описание того, что значит быть матерью (это значит быть женщиной и быть одним из родителей). Это утверждение выражает высказывание, которое, как мы предполагаем, должно быть истинным, и, кроме того, указывает, как показать, что кто-то является матерью. Аналогично, утверждения;
присоединить([], X, X).
присоединить([А|В],С[А|D]):- присоединить (B,C,D).
говорят о том, что собой представляет добавление одного списка в начало другого списка. Если пустой список помещается в начало некоторого списка X, то результатом будет X. С другой стороны, если непустой список присоединяется в начало некоторого списка, то головой списка-результата будет голова присоединяемого списка. Кроме того, хвостом списка-результата будет список, получаемый в результате присоединения хвоста первого списка ко второму списку. Можно считать, что эти утверждения описывают отношение присоединить, так же как и (возможно) то, как в действительности присоединить один список к другому.
Это все верно лишь для некоторых программ на Прологе. А какое возможное логическое значение можно приписать утверждениям подобным следующим?
memberl(X, List):- var(List),!,fail.
memberl(X,[X|_]).
memberl(X,[_|List]):- memberl(X,List).
print(0):-!.
print(N):- write(N), N1 is N-1, print(N1).
noun(N):- name(N,Name1), append(Name2, [ll5],Namel), name(RootN,Name2), noun(RootN).
implies(Assum,Concl):-asserta(Assum), call(Concl), retract(Concl).
Эта проблема имеет место для всех «встроенных» предикатов, используемых в программах на Прологе. Предикат подобный Var(List)ничего не говорит о принадлежности элемента списку, а проверяет состояние переменной (является ли указанная переменная неконкретизированной), возникающее в процессе доказательства. Аналогично, «отсечение» говорит кое-что о доказательстве высказывания (выбор каких альтернатив можно игнорировать), а не о самом этом высказывании. Два указанных «предиката» можно рассматривать как способ выражения управляющей информации о том, как должно выполняться доказательство. Точно так же, предикаты подобные write(N)не имеют каких-либо интересных логических свойств, но заранее предполагают, что в ходе доказательства будет достигнуто определенное состояние ( Nконкретизируется) и начинают обмен информацией с программистом, сидящим за терминалом. Целевое утверждение name(N, Name1)говорит кое-что о внутренней структуре объекта, который в исчислении предикатов был бы неделимым символом. В Прологе можно преобразовывать символы в строки литер, структуры в списки и в утверждения. Эти операции нарушают замкнутость высказываний исчисления предикатов. В последнем примере, использование предиката assertaозначает, что правило, о котором идет речь, добавляет что-то к множеству аксиом. В логике каждое правило или факт сохраняет истинность независимо от того, существуют ли какие либо другие факты или правила. В данном случае мы имеем дело с правилом, которое грубо нарушает этот принцип. Кроме того, если мы используем это правило, то окажемся в ситуации, когда на разных этапах доказательства имеется различное множество аксиом. Наконец, то что в одном из правил предполагается использовать терм Conclв качестве целевого утверждения, означает, что допускается, чтобы переменная обозначала высказывание, встречающееся в некоторой аксиоме. Такая конструкция не относится к числу тех, которые могут быть выражены на языке исчисления предикатов, но напоминает возможности, которые могут быть представлены логикой более высокого порядка.
На приведенном примере можно видеть, что некоторые программы на Прологе, можно понять лишь в терминах, описывающих что и когда может произойти при выполнении программ и каким образом программы сообщают системе о том, что нужно делать. В качестве крайнего случая, можно привести программу для генатом представленную в гл. 7. Вряд ли вообще может быть дана какая-либо декларативная интерпретация этой программы. Имеет ли тогда смысл рассматривать Пролог как язык логического программирования? Можем ли мы реально надеяться на какие-то преимущества логического программирования применительно к нашим программам на Прологе? На оба этих вопроса можно дать положительный ответ и основанием для этого служит то, что приняв соответствующий стиль программирования, мы все же можем получить некоторые преимущества благодаря связи Пролога с логикой. Ключевым моментом является использование разбиения программ на части, ограничивающие использование нелогических операций небольшим множеством утверждений. В качестве примера в гл. 4 было показано, как в некоторых случаях «отсечение» может быть заменено предикатом not.В результате таких замен, программу, содержавшую целый ряд «отсечений» можно свести к программе, в которой «отсечение» используется лишь однажды (в определении not).Использование предиката notдаже если он не совсем точно соответствует логическому '~' позволяет восстановить часть логической основы программы. Аналогично, ограничивая область применения предикатов assertaи retractопределениями небольшого числа предикатов (таких как генатоми найтивсе),можно добиться того, что в целом программа становится более понятной по сравнению с программой, в которой эти предикаты свободно используются где угодно.
Читать дальше