Министерство образования и науки РФ Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования Самарский государственный архитектурно-строительный университет Факультет информационных систем и технологий Кафедра прикладной математики и вычислительной техники ПРАКТИКУМ РЕШЕНИЯ ЗАДАЧ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА С ИСПОЛЬЗОВАНИЕМ ЯЗЫКА ПРОЛОГ Учебно-методическое пособие по организации самостоятельной работы студентов Прохорова О.В. 2012г. Рассматривается решение простых задач искусственного интеллекта с применением языка ПРОЛОГ. При этом изучается синтаксис и семантика языка. Особое внимание уделяется решению задач с организацией структур и списков. Оглавление 1. Базовые понятия языка Пролог .......................................................................................................... 3 1.1. Факты ................................................................................................................................................. 3 1.2. Вопросы ............................................................................................................................................. 5 1.3. Переменные...................................................................................................................................... 5 1.4. Конъюнкция целей ........................................................................................................................... 7 1.5. Правила ............................................................................................................................................. 8 1.6. Конъюнкция в правилах.................................................................................................................10 1.7. Переменные в теле правила .........................................................................................................12 2. Синтаксис ПРОЛОГА ...........................................................................................................................13 2.1. Константы ........................................................................................................................................13 2.2. Переменные....................................................................................................................................14 2.3. Структуры ........................................................................................................................................15 2.4. Операторы - тоже функторы ..........................................................................................................17 2.5. Арифметика.....................................................................................................................................18 2.6. Операции сравнения ......................................................................................................................19 2.7. Сопоставление ................................................................................................................................20 2.8. Второе значение операции = в Прологе .......................................................................................24 2.9. Примеры сопоставления структур ................................................................................................24 3. Декларативная семантика Пролог-программ .....................................................................................25 3.1. Дизъюнкция целей .........................................................................................................................28 3.2. Процедурная семантика ................................................................................................................29 3.3. Соотношение между процедурным и декларативным смыслом ..............................................33 4. Организация работы со списками в Прологе .....................................................................................35 4.1. Представление списка диаграммой .............................................................................................35 4.2. Процедуры обработки списков .....................................................................................................38 4.3. Встроенные предикаты ..................................................................................................................43 4.4. Ввод-вывод списков ......................................................................................................................44 Литература .................................................................................................................................................46 2 1. Базовые понятия языка Пролог Пролог - это язык программирования, используемый для решения задач, в которых действуют объекты и отношения между этими объектами. Программа на прологе состоит из предложений, которые могут быть фактами, правилами или вопросами. Родственные отношения Рассмотрим дерево родственных отношений: 1.1. Факты Введем отношение -родитель- (parent) между объектами. parent (tom, bob). 3 Это факт, определяющий , что Том является родителем Боба. parent - имя отношения, tom, bob - его аргументы. Теперь можно записать программу, описывающую все дерево родственных отношений. parent (pam, bob). parent (tom, bob). parent (tom, liz). parent (bob, ann). parent (bob, pat). parent (mary, ann). parent (pat, juli). Эта программа состоит из семи предложений (утверждений). Каждое утверждение записано фактом в виде отношения parent. При записи фактов надо соблюдать следующие правила: Имена всех отношений и объектов с маленькой буквы. Сначала записывается имя отношения, затем в круглых скобках через запятую объекты. В конце ставится точка. Еще пример факта: like (bob, pam). Совокупность фактов в прологе называют базой данных. 4 1.2. Вопросы К составленной базе данных можно задать вопросы. . Вопрос в обычном прологе начинается с ?Вопрос записывается также, как и факт. Например: ? - parent (bob, pat). yes Когда пролог получает вопрос, он пытается сопоставить его с базой данных. Такой факт находится, ответ: да (yes). ?-parent (bob,mary). no Ответ будет нет (no), так как такого факта в базе данных нет. 1.3. Переменные Можно задать вопрос и узнать, кто родитель liz: 5 ?-parent (X, liz). X= tom Здесь X - переменная. Ее величина неизвестна и она может принимать значения. В данном случае ее значением будет объект, для которого это утверждение истинно. ?-parent (X, bob). X=tom X=pam Можно задать вопрос, кто является чьим родителем. Или найти такие X и Y, что X является родителем Y. ?-parent (X, Y). X= pam Y= bob Y= tom X= bob и т.д. 6 1.4. Конъюнкция целей Можно задать более общий вопрос: Кто является родителем родителя juli. Так как нет отношения grandparent, то можно разбить на два вопроса: 1. кто родитель juli. Предположим- Y. 2. кто родитель Y. Предположим- X. ?-parent (Y, juli), parent (X, Y). X=bob Y=pat При поиске решения сначала находится Y , а затем по второму условию Х. Вопрос: Кто внуки тома?: ?-parent (tom, Y), parent (Y, X). Y=bob X=ann Y=bob X=pat И наконец, есть ли у ann и pat общий родитель? 7 ?-parent (Y, ann), parent(Y, pat). Y=bob 1.5. Правила Введем отношение peбенок child, обратное к parent "родитель". Можно было бы определить аналогично: child (liz, tom). Но можно использовать, что отношение child обратно к parent и записать в виде утверждения- правила : child(Y, X):-parent (X, Y). Правило читается так: Для всех X и Y Y -child X, если X -parent Y. Правило отличается от факта тем, что факт всегда истина, а правило описывает утверждение, которое будет истинной, если выполнено некоторое условие. Поэтому в правиле выделяют: голову и тело. child(Y, X) :- parent (X, Y). голова - head тело - body 8 Если условие parent (X, Y). выполняется, то логическим следствием из него будет утверждение child(Y, X). Рассмотрим, как правило используется прологом. Зададим вопрос ?-child(liz, tom). В программе нет данных о child. Но есть правило, которое верно для всех X Y, в том числе для liz и tom. Мы должны применить правило для этих значений. Надо подставить в правило вместо X- tom, a вместо Y - liz. Говорят, что переменные будут связаны, а операция будет называться подстановкой. Получаем конкретный случай для правила child(liz, tom):-parent (tom, liz). Условная часть приняла вид parent (tom, liz). Теперь надо выяснить выполняется ли это условие. Исходная цель child(liz,tom) заменяется подцелью parent (tom, liz)., которая выполняется, поэтому пролог ответит "yes". 9 1.6. Конъюнкция в правилах Добавим еще одно отношение в базу данных, унарное, определяющее пол. male(tom). male(bob). male(jim). female(liz). female(pam). female(pat). female(ann). Теперь определим отношение mother. Оно описывается следующим образом: Для всех X Y X -mother Y, if X- parent Y и X -female. Таким образом, правило принимает вид: mother(X, Y):-parent(X, Y), female(X). Можно записать mother(X, Y):-parent(X, Y), female(X). Запятая между двумя условиями означает конъюнкцию целей. Это означает, что два условия должны быть выполнены одновременно. 10 Как система ответит на вопрос? ?-mother (pam, bob). yes Сначала находится правило mother, затем производится подстановка X=pam Y=bob Получается правило mother(pam, bob):parent(pam, bob), female(pam). Сначала удовлетворяются parent , а затем female Пролог отвечает: yes Вопрос : ?-mother (X, bob). X=pam 11 1.7. Переменные в теле правила Определим отношение sister Для любых X и Y X sister Y, if у X и Y есть общий родитель, и X female Запишем правило на Прологе sister (X, Y):- parent(Z,X), parent(Z,Y), female(X). Здесь Z-общий родитель. Z-некоторый, любой. Можно спросить ?-sister(ann, pat). yes ?-sister(pat, pat). yes Ответ будет "yes". Так как мы не потребовали, чтобы X и Y были разные. Добавим отношение different (X, Y), которое указывает,что X и Y разные. sister (X, Y):- parent(Z,X), parent(Z,X), female(X), different (X, Y). 12 2. Синтаксис ПРОЛОГА Программа на прологе состоит из предложений . Предложения трех видов: факты, правила, вопросы. Все предложения строятся из термов. Терм является синтаксической единицей. 2.1. Константы Константы - это поименованные конкретные объекты или отношения. Атомы - аналогичны атомам или символам в лиспе. Атомы могут задаваться: 1) Цепочкой букв, цифр и символом подчеркивания '_', начиная со строчной буквы. a sister x_23 2) специальными символами*: = = => 13 Числа Целые ( диапазон -32768 32767) Действительные ( диапазон 1Е-307 1Е+308) 2.2. Переменные Переменные служат для обозначения объектов, значения которых меняются в ходе выполнения программы. Имена переменных могут начинаться: - или с прописной буквы - или с символа подчеркивания X Y Result _result Eсли значение переменной не интересует, то можно использовать анонимные переменные в виде символа подчеркивания '_'. Например, haschild(X):-parent(X, Y). Здесь значение Y не интересует, можно записaть haschild(X):-parent(X, _). Значение анонимной переменной не выводится на печать. Если несколько 14 анонимных переменных, то они все разные. Использование анонимных переменных позволяет не выдумывать имена переменных, когда не надо. Пусть задано отношение parents для двух родителей. parents(ann, tom, bob). Тогда в правиле: child(X):-parents(_, _, X). две анонимные переменные разные. ! Внимание. Область действия переменных - одно предложение. Одноименные переменные в разных предложениях могут иметь разные значения. 2.3. Структуры Структура - это единый объект состоящий из совокупности других объектов, называемых компонентами. Компоненты в свою очередь могут быть также структурами. Структура data: Название структуры стоит перед скобками, а компоненты внутри скобок, через запятую. Название структуры - ФУНКТОР. Структуры можно изображать в виде деревьев: 15 data / | \ 27 april 1992 Структура с компонентами – структурами может иметь вид: owns(bob, book(moby_dick, mell_will)). Структуры можно использовать для представления геометрических фигур. Объекты: точка Р1=point(1, 1) точка Р2=point(3, 3) отрезок seg(P1, P2) или seg(point(1, 1), point(3, 3)) треугольник triangle(point(2, 5), point(2, 8), point(5, 8)) Cтруктуру можно представить в виде дерева Корень дерева - главный функтор. Если точка трехмерного пространства: point3(X, Y, Z), то можно записать : point(X, Y, Z). Получается: point(X, Y, Z) и point(X, Y) Это разные термы, т.к. каждый функтор различается двумя параметрами: именем 16 арностью - т.е. числом атомов Удобно арность писать следующим образом: point/2 point/3 Например, если написано: Отношение point/2 задано .... Это означает, что задано point(_,_) , а не point/2(_,_). !!! Это типичная ошибка. 2.4. Операторы - тоже функторы Некоторые функторы удобнее записывать, как операторы. Например, можно записать +(1, 2) или + /\ 1 2 Удобнее записать 1+2 , т.е. в виде оператора. Причем надо понимать, что это не операция сложения, а операторная запись структуры. Такие операторы называются инфиксными. Аналогично операторная запись 2*a+b*c 17 может быть представлена в виде структуры: +( *(2, a), *(b, c)) Это и производит пролог при трансляции операторных выражений. Надо четко понимать, что операторы - это другая форма записи структуры. 2.5. Арифметика В Прологе выполняются следующие операции: + * / mod - остаток от целочисленного деления. Если записать: ?-X = 2+1. X=2+1 т.к. это просто сопоставление переменной и структуры. Чтобы арифметическое выражение рассчитывалось, необходимо использовать встроенный оператор is, который заставляет выполнять арифметические операции. ?-X is 2+1. X=3 ?-Y is 2*(5+6). Y=22 18 В функции могут быть переменные, но они должны иметь значение к моменту ее вычисления. f(X, Y, Z):-Z is X*X + Y*Y. Зададим вопрос ?- f(2, 3, R). R=13 Определим: sum(X1, X2, X):-X is X1 + X2. Тогда ?-sum(2, 3, X). X=5 ?- sum(1, 1, X1), sum(X1, X1, X). 4. 2.6. Операции сравнения Операции сравнения используются при сравнении чисел. Есть операции X>Y X<Y X >= Y X =< Y 19 равенство для любых термов X=Y X \= Y (с побочным эффектом) ?- 100 > 4. yes age(mary, 20). age(ann , 23). age(bob , 25). ?- age(X , Y), Y>21. X=ann; X=bob; ?- age(X , Y), Y>21, Y<=23. X=ann ; Определим отношение "выше" higher/2 higher(point(X1, Y1), point(X2, Y2):-Y1>Y2. ?- higher(point( 1, 1), point( 2, 2). no Если наоборот - то будет yes. 2.7. Сопоставление 20 Главной операцией в процессе выполнения Пролог - программы, является сопоставление (согласование, унификация) термов. Например, рarent(pam, bob). ?- parent(pam, bob). Yes Цель согласуется. ?-parent(pam, X). X=bob Атомы и переменные тоже согласуются, но X конкретизируется и принимает значение bob Но если взять два составных терма - структуры. a(b, C, d(e, F, g(h, i, J))) a(B, c, d(E, f, g(H, I, j))) cогласуются ли они? Что будет с переменными после согласования? Как они будут конкретизированны? Сопоставление - это процесс, на вход которого подаются два терма и процесс проверяет, соответствуют ли эти термы друг другу. Если термы не сопоставимы, значит сопоставление терпит неудачу. Если термы сопоставимы, тогда пpоцесс сопоставления находит конкретизацию переменных, делающих эти термы тождественными, и завершается удачей. 21 Какие же правила определяют сопоставимость двух термов S и Т ? 1. Если S и Т константы , то S и Т cопоставимы, только, если они являются одним и тем же объектом. т.е.: 2 сопоставляется с 2 bob сопоставляется с bob 2. Если S переменная, а Т -произвольный объект, то ни сопоставимы и S приписывается значение T. Наоборот, если Т -переменная, а S произвольный объект, то T приписывается значение S. Говорят,что T конкретизируется значением S. т.е.: data(M, D, 1992). data(may, 3, Y). 3. Сопоставимые переменные конкретизируются: М=may D=3 Y=1992 в обоих термах. 4. Если S и Т - структуры, то они сопоставимы, если (а) S и Т имеют одинаковый главный функтор и (b) все их соответствующие компоненты сопоставимы. Результирующая конкретизация определяется сопоставлением компонент. Если сопоставить структуры a(b, C, d(e, F, g(h, i, J))) a(B, c, d(E, f, g(H, I, j))) 22 то получим B=b C=c E=e F=f H=h I=i J=j Рассмотрим более сложный пример: triangle(point(2, 5), A, point(B, 8)) triangle(X, point(2, 8), point(5, 8)) После конкретизации X=point(2, 5) A=point(2, 8) B=5 Если Y представляет собой не конкретизированную переменную, а переменная X конкретизированную, то X и Y согласуются и принимают значение Х: X=2 Y=2 Переменные Z и A обе не конкретизированы. Они согласуются и становятся сцепленными. Если две переменные сцеплены, то при конкретизации одной из них, второй переменной автоматически будет присвоено то же самое конкретное значение, что и первой. Как это было с X и Y. 23 2.8. Второе значение операции “=” в Прологе В Прологе операция “=” кроме сравнения выполняет сопоставление двух термов, с конкретизацией переменных. Если термы согласуются, то результат - истина. ?-a(B,c(x,D))=a(d,c(X,3)). Yes B=d X=x D=3 Аналогично, /= дает истину, если термы не согласуются. ?-a(x)/=a(d). Yes 2.9. Примеры сопоставления структур Рассмотрим структуры, описывающие отрезки 24 Два факта ,описывающие свойство вертикальность и горизонтальность. vertical(seg(point(X,Y),point(X,Y1))). horiz(seg(point(X,Y),point(X1,Y))). ?-vertical(seg(point(2,2),point(2,5))). Yes ?- horiz(seg(point(1,4),point(2,4))). Yes ?-horiz(seg(point(1,4),point(2,X))). X=4 3. Декларативная семантика Пролог-программ Различают декларативную и процедурную семантику (смысл, понимание) пролог-программ. Рассмотрим декларативный смысл более подробно. Декларативный смысл, касается только отношений, определенных в программе. Декларативная семантика определяет, что должно быть результатом работы программы, не вдаваясь в подробности, как это достигается. 25 Пусть задано P:-Q, R. где P, Q, R -термы. Тогда с точки зрения декларативного смысла это предложение читается:" Pистиино, если Q R истинны." Или " Из Q и R cледует Р." Т.е. определяются логические связи между головой предложения и целями в его теле. Таким образом, декларативный смысл программы определяет, является ли данная цель истинной (достижимой), и если - да, то при каких значениях переменных она достигается. Конкретизацией I предложения С называется результат подстановки в него на место каждой переменной некоторого терма. Заметим , что это отличается от конкретизации переменной. Пример: haschild( X ):-parent( X ,Y). Предложение С. 26 Определение. Пусть дана некоторая программа и цель G, тогда в соответствии с декларативной семантикой, можно утверждать, что: Цель G истинна ( достижима ) тогда и только тогда, когда: в программе существует предложение С, такое, что существует такая его (С) конкретизация I, что голова I cовпадает с G и все цели в теле I истинны. Пример. 27 female(ann). C(I): parent(ann, bob). C: mother(ann):-parent(ann, Y), female(ann). mother(X) :-parent(X, Y), female(X). ?- mother(ann). Это определение можно распространить на вопросы следующим образом. В общем случае вопрос - список целей, разделенных запятыми. Список целей называется истинным (достижимым), если все цели в этом списке истинны, достижимы при одинаковых конкретизациях переменных. Запятая между целями означает конъюнкцию целей и они должны быть все истинны. 3.1. Дизъюнкция целей Возможна дизъюнкция целей: истинна должна быть по крайней мере одна из целей. Дизъюнкция обозначается точкой с запятой ";". Например: P:-Q;R. Читается: Р истина, если Q - истина или R - истинна. Т.е это то же самое, что 28 P:-R. P:-Q. Запятая связывает цели сильнее, чем точка с запятой. Таким образом предложение: P:-Q, R;S, T, U. понимается как P:-(Q, R);(S, T, U). и имеет смысл P:-Q, R. P:-S, T, U. 3.2. Процедурная семантика Процедурная семантика (процедурный смысл) пролог-программы определяет, как пролог-программа отвечает на вопросы. Ответить на вопрос - это значит удовлетворить цели. Поэтому процедурная семантика пролога - это процедура вычисления списка целей с учетом программы. 29 Рассмотрим программу и на ее примере - процедуру вычисления списка целей. Входом процедуры являются программа и список целей, выходом процедуры являются признак успех / неуспех и подстановка переменных. Подстановка переменных порождается только в случае успешного завершения. Рассмотрим пример, иллюстрирующий процедурную семантику Пролога: Программа: большой (медведь). % факт 1 большой (слон). % факт 2 маленький (кот). % факт 3 коричневый (медведь). % факт 4 черный (кот). % факт 5 серый (слон). % факт 6 темный (Z):- черный ( Z). % правило 1: темный (Z):- коричневый (Z). % правило 2: 30 ?- темный (Х), большой (Х) % кто одновременно темный и %большой? Шаги вычисления: Исходный список целевых утверждений: темный (Х), большой (Х). Просмотр всей программы от начала к концу и поиск предложения, у которого голова совпадает с первым целевым утверждением темный (Х). Найдено правило 1: темный (Z):- черный( Z). Порождается новый список целевых утверждений черный (Х), большой (Х) Просмотр программы для нахождения предложения, сопоставимого с черный (Х). Найдено предложение 5: черный (кот). У этого предложения нет тела, поэтому список целей при соответствующей конкретизации сокращается до большой (кот) Просмотр программы в поисках цели большой (кот). Ни одно предложение не найдено. Поэтому происходит возврат к шагу (3) и отмена конкретизации Х = кот. Список целей теперь снова черный (Х), большой (Х) 31 Продолжение просмотра программы ниже факта 5. Ни одно предложение не найдено. Поэтому возврат к шагу (2) и продолжение просмотра ниже правила 1. Найдено Правило 2: темный (Z), коричневый (Z) Замена первой цели в списке на коричневый (Х) дает коричневый ( Х), большой( Х) Просмотр программы для обнаружения предложения, сопоставимого коричневый (Х). Найдено предложение коричневый (медведь). У этого предложения нет тела, поэтому список целей уменьшается до большой (медведь) 6. Просмотр программы и обнаружение факта большой (медведь). У него нет тела, поэтому список целей становится пустым. Это указывает на успешное завершение процедуры. Таким образом, для вычисления целей потребовалось 7 сопоставлений и один откат. Рассмотрим список целей: G1 G2 … Gm 1.Если список целей пуст, то имеем успех, если нет, то выполнятся пункт 2. 2.Берется первая цель G1 из списка. Пролог выбирает в базе данных, просматривая сначала, первое предложение С: 32 С :- B1, B2, ..., Bn голова которого, сопоставляется с целью G1. Если такого предложения нет, то неудача. Если есть, то переменные конкретизируются, и цель G1 заменяется на список целей B1 … B2 Bn с конкретизированными значениями переменных. 3.Рассматривается рекурсивно через п.2 новый список целей. B1 B2 … Bn G2 … Gm Если С -факт, то новый список короче на одну цель. Если вычисление нового списка оканчивается успешно, то и исходный список целей выполняется успешно. Если нет, то новый список целей отбрасывается, снимается конкретизация переменных и происходит возврат к просмотру программы, но начиная с предложения, следующего за предложением С. 3.3. Соотношение между процедурным и декларативным смыслом Создавая пролог программы всегда надо помнить о процедурном и декларативном смысле. Декларативный смысл касается отношений, определенных в программе. Другими словами декларативный смысл определяет, что должно быть результатом программы. 33 С другой стороны, процедурный смысл определяет, как этот результат может быть достигнут, т.е., как реально отношения обрабатываются Прологом. 34 4. Организация работы со списками в Прологе Список записывается на Прологе [a,b,c], т.е. элементы записываются в квадратных скобках через запятую. Элементами списка могут быть любые термы. Пустой список – представляется, как [ ]. 4.1. Представление списка диаграммой Список в Прологе может определяться через функтор "." (точка). .(a,[ ]) это форма записи списка. Список [a,b,c] может быть представлен структурой .(а ,.(b,.(c,[ ]))) или в виде дерева, или диаграммой "виноградная лоза" 35 Для вложенных списков [a,b,[c,d]] - на верхнем уровне три элемента - на втором уровне два элемента. Главной операцией при работе со списками является расщепление списка на голову и хвост. 36 В Прологе имеется специальная форма представления списка, называемая cons-формой записи: [Head|Tail] или [H|T] или [a|[ ]] = [а] При конкретизации формы списка H сопоставляется с головой списка, а Т - с хвостом. Например. р([a,b,c]). ?-p([X|Y]). yes X=a Y=[b,c] Таким образом, выделяются одновременно голова списка и хвост. Шаблон (образец) списка - это форма описания множества (семейства) списков, обладающих определенными свойствами. Например: Шаблон списка [X|Y] описывает любой список, состоящий не менее чем из одного элемента. Шаблон [X,Y|Z] - список, состоящий не менее чем из двух элементов. Шаблон [b|Z] - список, первым элементом которого является b. Шаблон [Y,X,Z] - список из трех элементов. Шаблоны списка используются при описании процедур работы со списками. 37 Задача 1: Определить отношение replace_first, которое заменяет первый элемент списка новым Например . ?-replace_first([a,b,с],w,X). X=[w,b,c] Что будет ответом для следующего вопроса ? ?-replace_first([_|T],A,[a,b,c]). 4.2. Процедуры обработки списков Процедура в Прологе - это совокупность предложений с головами, представленными одинаковыми термами. Для обработки списков используются типовые процедуры. Например, процедура member(X, L) проверяет принадлежность элемента списку. Если X принадлежит L, то ответ - истина и ложь в противном случае. С точки зрения декларативного смысла: 1. X принадлежит списку, если X совпадает с головой списка. 2. X принадлежит списку, если X принадлежит хвосту списка. 38 Можно записать: member(X, [X|T]). member(X, [H|T]) :-member(X, T). С точки зрения процедурного смысла - это рекурсивная процедура. Первое предложение есть терминальное условие. Когда хвост будет равен [ ] проверка остановится. Второе предложение рекурсивное. Сокращение списка происходит за счет взятия хвоста (cdr-рекурсия). ?-member(a, [a, b, с]). Yes ?-member(X, [a, b, с]). Yes X=a X=b X=c Ответьте на вопрос: ?-member(a, X). Процедура append (L1, L2, L3) используется для соединения двух списков. L1 и L2 - списки, а L3 - их соединение. ?-append ([a, b], [c], [a,b,c]). Yes 39 Для определения процедуры append используем два предложения: 1. Если присоединить пустой список [ ] к списку L, то получим список L. append([], L, L). append([X|L1], L2, [X|L3]):- append(L1, L2, L3). 2. Если присоединить не пустой список [X|L1] к списку L2, то результатом будет список [X|L3], где L3 получаeтся соединением L1 и L2. С точки зрения процедурной семантики первое предложение - терминальное условие, второе - рекурсивное с хвостовой рекурсией. Рассмотрим примеры применения ?-append([a], [b, c], L). L=[a, b, c] ?-append([a], L, [a, b, c]). L=[b, c] ?-append(L, [b, c], [a, b, c]). L=[a] Эту процедуру можно использовать для разбиения списка на элементы 40 ?-append(L1, L2, [a, b, c]). L1=[] L2=[a, b, c]; L1=[a] L2=[b, c]; L1=[a, b] L2=[c]; L1=[a, b, c] L2=[] Процедуру арреnd можно использовать для поиска комбинаций элементов. Например, можно выделять списки слева и справа от элемента ?-append(L, [3|R], [1, 2, 3, 4, 5]). L=[1, 2] R=[4, 5] Можно удалить все, что следует за данным элементом и этот элемент тоже: ?-L1=[a, b, c, d, e], append(L2, [c|_], L1). L1=[a, b, c, d, e] L2=[a, b] Можно определить процедуру, выделяющую последний элемент в списке: last(X, L):-append(_, [X], L). 41 Процедура reverse обращает список. 1. Пустой список после обращения - пустой. reverse([ ], [ ]). 2. Обратить список [X|L1] и получить список L2 можно, если обратить список L1 в L3 и в хвост ему добавить X. reverse([X|L1], L2):-reverse(L1, L3), append( L3, [X], L2). Можно, используя рекурсивный вызов, подсчитать длину списка: length([], 0). length([X|L], N):-length(L, M), N is M+1. ?-length([a, b, c], N). N=3 42 4.3. Встроенные предикаты До сих пор мы получали ответы в форме предлагаемой прологом: 1. печатались значения переменных присутствующих в вопросе; 2. вопросы полностью записывались после запроса "?-". Однако можно задавать вопросы и получать ответы в произвольной форме. Для этого достаточно использовать встроенные предикаты. Встроенные предикаты – предикаты, определенные в Прологе, для которых не существует процедур в базе данных. Когда интерпретатор встречает цель, которая сравнивается с встроенным предикатом, он вызывает встроенную процедуру. Встроенные предикаты обычно выполняют функции не связанные с логическим выводом. Встроенные предикаты обеспечивают возможности ввода-вывода информации: 1. write/1 - этот предикат всегда успешен. Когда он вызывается, побочным эффектом будет вывод значения аргумента на экран. 2. nl/0 - этот предикат всегда успешен. Когда он вызывается, то побочным эффектом будет перевод на следующую строку. 3. tab/1 - этот предикат всегда успешен. Когда он вызывается, то побочным эффектом будет печать количества пробелов, заданное аргументом. Аргумент должен быть целым. 4. read/1 - этот предикат читает терм, который вводится с клавиатуры и заканчивается точкой. Этот терм сопоставляется с аргументом. Например, 43 pr1:- read(X),nl,write('X='),tab(2),write(X). При вызове ?-pr1. последовательность термов следующая: читается значение X; переводится строка; печатается 'X='; пропускается два пробела; печатается значение X. 4.4. Ввод-вывод списков Для ввода-вывода списков возможны следующие два способа. При этом способе список рассматривается как один терм. Например, процедура: pr:-write('Введите список L:'),nl, read(L),nl, write('Список L='), tab(2), write(L),nl. При вызове цели ?-pr. 44 процедура будет выполнять следующие действия: Введите список L: [a,b,c,d]. Список L= [a,b,c,d] Данный способ может быть организован с помощью рекурсивно определенных процедур. read_list([X|T]):-write('Введите элемент: '), read(X), X\==end,!, read_list(T). end - терм, означающий конец списка. read_list([]). write_list([]):-nil. write_list([H|T]):-write(H), tab(2), write_list(T). Тогда после вызова цели: ?-read_list(L),nl,write('Список='), write_list(L). Возникает следующий диалог: 45 Введите элемент: a. Введите элемент: b. Введите элемент: c. Введите элемент: d. Введите элемент: end. Список= a b c d Литература 1. http://www.mari-el.ru/mmlab/home/prolog/study_l.html 46