Механизм вывода в системе Пролог, страница 4

В Прологе имеются также операции "-", "*", "/". Заметим, что порядок аргументов в выражениях значения не имеет. Так, выражение Х = А*В идентично А*В = Х.. В Прологе применяются следующие функции, позволяющие вычислять:

mod, X mod Y - остаток от деления Х на Y;

div, X div Y - целую часть частного от деления Х на Y;

abs(X) - абсолютную часть числа;

ехр(Х) - возведение е в степень X;

sqrt(X) - значение квадратного корня от X;

sin(X), cos(X), tg(X), arctg(X) - тригонометрические функции.

Для арифметических операции установлен следующий приоритет:

1)+,-; 2)*,/; 3)mod, div; 4)+,-(одноместные).

Рассмотрим применение арифметических операций "-" и "*" для вычисления факториала числа. Известно, что 1!=1 и n!=n*(n-l)!

В предикате "fact(X,Y)" Y является факториалом числа X.

Первое утверждение на Прологе записывается в виде следующего факта: fact(1,1). Для записи второго утверждения нужно:

1) из n вычесть единицу, получая Z;

2) вычислить факториал Z, получая X1;

3) умножить X1 на n, получая Y.

Таким образом, имеем следующую программу:

predicates

fact(real,real)

clauses

fact(l,l).

fact(X,Y) :- Z=X-1, fact(Z,X1), Y=X*X1.

Введем запрос fact(5,X) и получим правильный ответ: Х=120.

Но система продолжает поиск других решений и в окне "Message" выдает сообщение о том, что стек перепол­нен и нужно нажать клавишу ПРОБЕЛ.

Здесь не указано ограничение поиска, система продолжает уменьшать Х на единицу и пытается унифицировать это-результат с первым фактом fact(l.l). Для указания останова поиска есть несколько способов. Так, можно задать в первом факте предикат отсечения:

fact(l,l) :- !.

или этот предикат указать во втором правиле:

fact(X,Y) :- Z = X - 1, fact(Z,X1), !,Y = X*X1.

Можно задать условие, чтобы оставшееся значение превышало единицу:

fact(X,Y) :- Х>1, Z = X - 1, fact(Z,X1), Y = X*X1.

Пример 4.6

Вычислить 5!:

5! = 5   *   4!  или

   4!  =   4   *   З! или

       З!  =   3   *   2! или

           2!  =   2   *   1! или

               =   1!  =   1 т.е.

2!  =   2   *   1   =   2 т.е.

З!  =   3   *   2   =   6 т.е.

4!   =   4   *   6   =   24 т.е.

5! = 5   *   24  =   120

В выражениях применяются логические операции: ум­ножение (обозначается знаком "," ), сложение (обозначается знаком ";" ), отрицание. Так, используя операцию ИЛИ, прави­ла

родители(Х, Y) :-отец(Х,Y).

родители(Х, Y) :- мать(Х,Y).

можно записать в виде

родители(Х,Y) :- отец(Х,Y); мать(Х,Y).

Операция отрицание обозначается предикатом "not". Так, утверждение not отец (a,d) истинно, если факт отец(а,d) отсутствует в БД.

Для сравнения значений применяются следующие опе­рации отношений:

“>”,”>=”,”<”,”<=”,”=”,”<>” или “><” (не равно).


Обработка списков и строк символов

Список в Прологе представляется множеством элемен­тов, разделенных запятой и ограниченных квадратными скоб­ками.

Так, X = [a,b,c,d] является списком из четырех элементов.

Для разделения списка на части используется предикат "|" (вертикальная черта). Этот предикат разделяет список на голову и хвост. Головой списка может быть его первый эле­мент, тогда хвост списка есть подсписок, состоящий из всего списка за исключением его первого элемента. Так, если X=[a,b,c,d] и X=[Y|Z], то Y=a и Z=[b,c,d]. Заметим, что в слу­чае списка, состоящего из одного элемента, Х=[а] и X=[Y|Z], тогда Y=a и Z=[]-пустой список, который обозначают откры­вающей и закрывающей квадратными скобками. Поскольку список делится на части, то его можно составлять из отдель­ных частей. Так, например, из одного элемента и списка мож­но получить новый список.

Пусть: 1) Х=а, Y=[b,c,d] и Z=[X|Y], тогда Z=[a,b,c,d] и 2) Х=а, Y=b, тогда Z=[a|b], а не Z=[a,b]. В первом случае Y - спи­сок, а во втором Y - элемент. Таким образом, соединение двух элементов дает список, состоящий из элемента и подсписка, а не из двух элементов.

Далее в этом параграфе рассмотрим процедуры работы со списками. Во многих случаях, чтобы упростить изложение, будем приводить только часть clauses Пролог-программ.

Принадлежность элемента списку. Предположим, что имеется список наименований деталей велосипеда: руль, рама, колесо, седло, и нужно определить, содержится ли некоторая деталь, например "седло", в данном списке.

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

Принадлежность элемента Х списку Y можно записать в виде предиката "принадлежит(Х,Y)". Для определения истин­ности этого предиката требуется проверить два условия. Пер­вое состоит в проверке совпадения Х с головой списка X, что записывается на языке Пролог следующим образом:

принадлежит(Х,[Х|_]).

Для обозначения хвоста списка здесь используется ано­нимная переменная "_". Данный факт можно записать в виде правила:

принадлежит(Х,[Y|_]) :- X = Y.

Для определения принадлежности элемента Х хвосту списка будем использовать тот же предикат "принадлежит", в чем и заключается суть рекурсии. На Прологе это записывает­ся правилом

принадлежит(Х,[_|Y]) :- принадлежит(Х,Y).

что означает: "X является элементом списка, если Х является элементом хвоста списка". В качестве головы списка применя­лась анонимная переменная, так как ее имя значения не имеет.