- •2.2.2.1 Вызов Турбо-Пролога и главное меню системы
- •2.2.3 Редактор Турбо-Пролога
- •2.2.3.1 Создание и редактирование программного файла
- •3 Лекция №2. Элементы и конструкции языка Турбо-Пролог
- •3.1 Основные вопросы
- •3.2 Текст лекции
- •3.2.1.1 Имена (идентификаторы)
- •3.2.2.1 Предикаты
- •3.2.2.2 Факты
- •3.2.2.3 Правила
- •3.2.2.4 Цели
- •4 Лекция №3. Объекты данных. Константы, переменные, структуры, списки.
- •4.1 Основные вопросы
- •4.2 Текст лекции
- •Стандартные типы доменов Турбо-Пролога
- •4.2.2.1 Константы
- •4.2.2.2 Переменные
- •4.2.2.3 Структуры
- •4.2.2.3 Списки
- •5 Лекция №4. Структура программы на Турбо-Прологе
- •5.1 Основные вопросы
- •5.2 Текст лекции
- •5.2.2 Структура программы на Турбо-Прологе – до 10 мин.
- •5.2.3.1 Раздел опций компилятора
- •5.2.3.2 Раздел констант
- •5.2.3.3 Раздел доменов
- •5.2.3.4 Раздел предикатов
- •5.2.3.5 Раздел утверждений
- •5.2.3.6 Раздел дбд
- •5.2.3.7 Раздел целей
- •6 Лекция №5. Унификация и поиск с возвратом: программа с фактами
- •6.1 Основные вопросы
- •6.2 Текст лекции
- •7 Лекция №6. Унификация и поиск с возвратом: программа с фактами и правилом
- •7.1 Ключевые (основные) вопросы (моменты)
- •7.2 Текст лекции
- •8 Лекция №7. Унификация и поиск с возвратом: программа с фактами и несколькими правилами
- •8.1 Основные вопросы
- •8.2 Текст лекции
- •9 Лекция №8. Вопросно-ответные системы
- •9.1 Основные вопросы
- •9.2 Текст лекции
- •10 Лекция №9. Средства отладки в Турбо-Прологе
- •10.1 Основные вопросы
- •10.2 Текст лекции
- •/*Программа 5 */
- •11 Лекция №10. Простейший ввод-вывод. Окна.
- •11.1 Основные вопросы
- •11.2 Текст лекции
- •11.2.1 Простейший ввод-вывод
- •11.2.2 Окна
- •12 Лекция №11. Управление поиском решений: предикаты отсечения и возврата
- •12.1 Основные вопросы
- •12.2 Текст лекции
- •/* Программа 5 */
- •Vse_reshenia:-roditel(X,y), write(X, "родитель", y), nl, fail.
- •Vita - родитель sasha
- •/* Программа 6 */
- •/* Программа 7 */
- •13 Лекция №12. Арифметика в Турбо-Прологе. Рекурсия.
- •13.1 Основные вопросы
- •13.2 Текст лекции
- •/* Программа 8 */
- •/* Программа 9 */
- •14 Лекция №13. Динамические базы данных
- •14.1 Основные вопросы
- •14.2 Текст лекции
- •/* Программа работы с дбд*/
- •15 Лекция №14. Работа со списками
- •15.1 Основные вопросы
- •15.2 Текст лекции
- •/* Программа 10*/
- •/* Программа 11 */
- •/* Программа 12 */
- •16 Лекция №15. Экспертные системы
- •16.1 Основные вопросы
- •16.2 Текст лекции
- •/* Программа эс*/
15 Лекция №14. Работа со списками
Время: 2 часа (90 мин.)
15.1 Основные вопросы
- обработка списков.
15.2 Текст лекции
Описание предиката списка аналогично описанию обычного предиката. Пусть, например, имеется список марок автомобилей, определяемый предикатом car:
car(["Жигули", "Волга", "BMW", "Ford"]).
Рассмотрим программу, обеспечивающую простейшую обработку данного списка:
/* Программа 10*/
domains
car_list = car_name*
car_name = sybol
predicates
car(car_list)
clauses
car(["Жигули", "волга", "BMW", "Ford"]).
В разделе domains определён домен car_list с указанием того, что это список, состоящий из элементов сar_name. Символ "*", после имени car_name обозначает, что это элементы списка. Тип домена элементов списка (symbol) указан в следующей строке.
В разделе predicates в скобках после имени предиката car указывается имя домена списка. В разделе clauses приводится сам список.
Замечание: описание типа домена списка в разделе domains можно упростить следующим образом:
domains
car_list = symbol
Однако в этом случае опускается смысловое содержание элементов списка, что может затруднить "чтение" программы. Но если программа небольшая, то такой вариант описания домена списка вполне допустим.
Поскольку в программе 10 нет раздела goal, можно делать внешние запросы, например:
Goal:car(X)
В ответ на такой запрос система выдаст полный список марок автомобилей:
X=["Жигули", "Волга", "BMW", "Ford"]
1 Solution
На запросы, приводимые ниже, можно получить значения одного или нескольких элементов списка:
Goal:car([_, A2, _, _])
A2="Волга"
1 Solution
Goal:car([A1, A2, _, _])
A1="Жигули", A2="Волга"
2 Solutions
В подобных запросах важно правильно указать позиции искомых элементов списка и общее количество элементов в нём. Например на вопрос car([A1, A2, A3]) не будет получен ответ из-за несоответствия количества элементов в списке и в целевом утверждении.
Однако Турбо-Пролог позволяет производить операции над списками и при неопределённом числе элементов. Применяемый в этом случае метод получил название метода разделения списка на голову и хвост. Суть метода заключается в отделении первого элемента списка (головы) для его обработки и последующего деления оставшейся части списка (хвоста) на новую голову и новый хвост, вплоть до полного исчерпания списка.
Для иллюстрации метода рассмотрим, например, программу определения длины списка (т.е. количества его элементов):
/* Программа 11 */
domains
spisok = symbol*
predicates
dlina(spisok, integer)
clauses
dlina([ ], 0).
dlina([_, X ], L) :- dlina(X, Lhvosta), L=Lhvosta + 1.
В программе определён предикат dlina, аргументами которого являются список символических имён и целое число. Аргумент spisok соответствует реальному списку, обрабатываемому программой, а целое число определит его искомую длину.
Первое предложение в clauses утверждает, что длина пустого списка равна нулю. Второе предложение определяет правило вычисления длины списка. В заголовке правила список разделён на голову и хвост ([ _ | X ]). Голова обозначена анонимной переменной, а хвост переменной X. Очевидно, что аргументу [ _ | X ] предиката dlina удовлетворит любой непустой список, связывая переменную X с хвостом этого списка. При этом каков первый элемент списка (т.е. его голова) не является существенным, на что и указывает анонимная переменная.
Первая подцель правила - это рекурсивное повторение самого правила, где в качестве объекта предиката dlina указан хвост списка X. При рекурсивном возврате к заголовку правила хвост списка снова будет делится на голову и новый хвост, т.е. произойдёт отделение следующего элемента от списка. Этот процесс будет продолжаться до полного исчерпания списка, а при каждом рекурсивном возврате к заголовку правила новые копии переменной Lhvosta будут помещаться в стек.
После исчерпания всего списка (т.е. тогда, когда список станет пустым) будет унифицировано первое предложение раздела clauses и переменная Lhvosta получит значение равное нулю. После этого осуществиться переход к рекурсивному правилу и начнётся выполнение его второй подцели, т.е. определение длины списка за счёт рекурсивного сворачивания данных из стека.
Ниже на примере описан процесс определения длины списка. Допустим мы сформулировали внешний запрос:
Goal: dlina([a, b, c, d],LN)
Тогда рекурсивное исчерпание списка будет условно выглядеть следующим образом:
dlina([a | [b, c, d],L1)
dlina([b, [c, d],L2)
dlina([c, [d],L3)
dlina([d, [],L4)
dlina([],0)
Условное же представление вычисления длины списка будет выглядеть так:
L4 = 0 + 1 = 1
L3 = L4 + 1 = 2
L2 = L3 + 1 = 3
L1 = L2 + 1 = 4
в результате на введённый запрос система выдаст ответ:
LN=4
1 Solutions
Рассмотрим теперь программы выполнения операций над списками. Ниже приведена программа, обеспечивающая операцию поиска элемента в списке: