Лаб. работа “Логическое программирование”
Задание №1: Введение в логическое программирование
Цель: Ознакомиться с основами логического программирования, средой разработки SWI-Prolog (SWI), основными операторами и принципами работы.
Теоретические сведения
Логическое программирование основано на декларативном подходе, где программы описывают факты и правила, а вычисления выполняются путем логического вывода. SWI-Prolog является одной из самых популярных реализаций языка Prolog.
Методические указания
Установите SWI-Prolog с официального сайта SWI-Prolog и убедитесь, что среда разработки работает корректно.
Ознакомьтесь с основными командами консоли SWI-Prolog:
consult('файл.pl').— загрузка программыlisting.— просмотр загруженных предикатовtrace.— включение пошаговой отладкиhalt.— завершение работы интерпретатора
Изучите формат записи фактов и правил. Например, определение семейных отношений:
Попробуйте выполнять простые запросы, например:
Используйте отладку (
trace.) для анализа работы программы.
Задания
- Установить SWI-Prolog и настроить среду.
- Определить простые факты и правила для предметной области «Семья» (родители, дети, братья, сестры).
- Реализовать простые запросы на выборку информации (например, “Кто является родителем Васи?”).
- Написать правила для определения предков и потомков.
Задание №2: Операции с фактами и правилами
Цель: Научиться работать с фактами, правилами и предикатами, применять логические выражения в Prolog.
Теоретические сведения
Факты и правила формируют базу знаний в Prolog. Факты представляют собой утверждения, а правила позволяют выводить новые знания. Предикаты используются для логических вычислений.
Задания
- Определить базу знаний для предметной области «Студенты и курсы» (студент, курс, оценки).
- Написать правила для определения успешности студентов.
- Реализовать предикат, проверяющий, сдал ли студент определенный курс.
- Написать запросы для получения списка студентов, сдавших конкретный курс.
Дополненная теоретическая информация для выполнения задания №2
2.1. Факты в Prolog
Определение: Факты — это базовые утверждения, описывающие статические знания. Они состоят из предиката и его аргументов.
Синтаксис:
Пример для предметной области “Студенты и курсы”:
Важно:
- Аргументы могут быть атомами, числами, строками или списками.
- Каждый факт заканчивается точкой.
- Регистр имеет значение:
mathиMath— разные атомы.
2.2. Правила в Prolog
Определение: Правила позволяют выводить новые знания на основе фактов и других правил. Они состоят из головы и тела, разделенных символом :-.
Синтаксис:
Пример правила для успешности студента:
Объяснение:
successful(Student, Course)— голова правила.
student(Student, Course, Grades)— извлечение оценок студента.
forall(member(Grade, Grades), Grade >= 4)— проверка, что все оценки ≥ 4.
2.3. Предикаты и логические выражения
Предикат — это именованная логическая функция, возвращающая true или false.
Логические операторы:
,— логическое И (конъюнкция).
;— логическое ИЛИ (дизъюнкция).
notили\+— отрицание.
Пример предиката для проверки сдачи курса:
Разбор:
sum_list/2иlength/2— встроенные предикаты для работы со списками.
is— оператор вычисления арифметических выражений.
2.4. Запросы к базе знаний
Запросы — это вопросы к базе знаний, которые проверяют истинность утверждений.
Пример запроса для списка студентов, сдавших курс математики:
Объяснение:
- Переменная
Nameавтоматически связывается с именами студентов.
- Символ
_означает анонимную переменную (значение не важно).
- Запрос вернет всех студентов, для которых выполнится
passed(Name, math).
Использование findall для сбора результатов:
2.5. Советы по реализации
Структура базы знаний:
- Разместите факты в начале файла, затем правила.
- Используйте списки для хранения оценок:
[4,5,3].
- Разместите факты в начале файла, затем правила.
Типичные ошибки:
- Забытая точка в конце факта/правила.
- Несовпадение числа аргументов в предикатах.
- Забытая точка в конце факта/правила.
Отладка:
- Используйте
trace.для пошагового выполнения.
- Проверяйте типы данных: например,
[4,5,3]— список, а4— число.
- Используйте
Пример полной программы:
% Факты
student(anna, math, [4,5,4]).
student(bob, math, [3,4,5]).
course(math, 2023).
% Правило для проверки успешности
successful(Student, Course) :-
student(Student, Course, Grades),
forall(member(Grade, Grades), Grade >= 4).
% Предикат для проверки сдачи курса
passed(Student, Course) :-
student(Student, Course, Grades),
sum_list(Grades, Sum),
length(Grades, N),
Average is Sum / N,
Average >= 3.5.
% Запрос: Найти всех, кто сдал математику
% ?- findall(Name, (student(Name, math, _), passed(Name, math)), Students).Результат выполнения запроса:
Самостоятельные задания для закрепления материала
Задание 2.1: Расширение базы знаний
Цель: Научиться структурировать данные и добавлять факты.
Описание:
- Добавьте в базу знаний 5 новых студентов с разными курсами и оценками.
- Создайте факты для 3 дополнительных курсов (например,
physics,history,programming).
- Включите информацию о годе обучения для каждого студента (например,
year(anna, 2)).
Пример:
Задание 2.2: Правила с условиями
Цель: Написать правила с использованием логических операторов.
Задачи:
- Создайте правило
can_graduate(Student), которое возвращаетtrue, если студент сдал все свои курсы.
- Определите предикат
has_scholarship(Student), который проверяет, что у студента средний балл ≥ 4.5.
- Реализуйте правило
retake(Student, Course), которое возвращаетtrue, если студент имеет хотя бы одну оценку < 3 по курсу.
Подсказка:
Используйте встроенные предикаты
findall,sum_list,length.
Пример для
has_scholarship:
Задание 2.3: Работа со списками
Цель: Освоить обработку списков в Prolog.
Задачи:
- Напишите предикат
best_student(Student), который находит студента с максимальным средним баллом.
- Создайте правило
passed_all(Students), возвращающее список студентов, сдавших все курсы.
- Реализуйте предикат
top_course(Course), который определяет курс с наивысшим средним баллом среди всех студентов.
Пример запроса:
Задание 2.4: Динамическое изменение базы знаний
Цель: Изучить модификацию фактов в runtime.
Задачи:
- Напишите правило
add_grade(Student, Course, Grade), добавляющее оценку в список оценок студента.
- Создайте предикат
remove_course(Student, Course), удаляющий курс из базы знаний.
- Реализуйте проверку на корректность оценок (например, оценка должна быть от 1 до 5).
Подсказка:
Используйте
assertz,retractдля изменения базы знаний.
Пример для
add_grade:
Задание 2.5: Творческое задание
Цель: Применить знания для моделирования реальных сценариев.
Задачи:
- Добавьте предикат
prerequisite(Course, RequiredCourse), который определяет обязательный курс для зачисления на другой (например, для курсаaiтребуетсяprogramming).
- Реализуйте правило
can_enroll(Student, Course), проверяющее, может ли студент записаться на курс (есть ли у него необходимые знания).
- Создайте предикат
recommend_course(Student, Course), который рекомендует курс на основе оценок студента (например, если студент хорошо знает математику, предложитьphysics).
Пример:
Задание 2.6: Тестирование
Цель: Научиться проверять корректность правил.
Задачи:
- Напишите 3 тестовых запроса для предиката
passed(Student, Course), которые проверяют:- Студент с оценками [5,5,5] сдал курс.
- Студент с оценками [3,3,4] не сдал курс.
- Студент с несуществующим курсом возвращает
false.
- Студент с оценками [5,5,5] сдал курс.
- Проверьте правило
successfulна крайних случаях (например, пустой список оценок).
Пример теста:
Задание 2.7: Оптимизация
Цель: Улучшить производительность запросов.
Задачи:
- Перепишите правило
passedбез использованияforall, заменив его на рекурсию.
- Реализуйте кэширование результатов для предиката
best_student, чтобы избежать повторных вычислений.
Подсказка:
- Используйте мемоизацию через
assertz.
Задание 2.8: Визуализация
Цель: Выводить результаты в удобном формате.
Задачи:
Напишите правило
print_students(Students), которое выводит список студентов в формате:Студент: Анна, Курс: math, Средний балл: 4.5Создайте предикат
generate_report(Course), который сохраняет в файл список сдавших курс.
Пример:
Бонусное задание: ИИ-ассистент
Цель: Реализовать простой диалог с пользователем.
Задачи:
- Напишите правило
ask_about_student, которое запрашивает имя студента и выводит его средний балл.
- Реализуйте диалог, где пользователь может задавать вопросы вида:
- «Кто сдал курс математики?»
- «Какой курс самый популярный?»
- «Кто сдал курс математики?»
Пример:
Задание №3: Рекурсия в Prolog
Цель: Освоить работу с рекурсией в логическом программировании.
Теоретические сведения
Рекурсия является основным механизмом итерации в Prolog. Предикаты могут вызывать сами себя, что позволяет реализовывать сложные вычисления без явного использования циклов.
Задания
- Реализовать предикат вычисления факториала числа.
- Написать предикат вычисления чисел Фибоначчи.
- Реализовать рекурсивный предикат для проверки, является ли список палиндромом.
- Написать предикат, находящий сумму элементов списка.
Дополненная теоретическая информация для задания №3
3.1. Основы рекурсии в Prolog
Рекурсия — это механизм, при котором предикат вызывает сам себя для решения подзадач. В Prolog рекурсия заменяет традиционные циклы и используется для:
- Обработки списков.
- Вычислений с накоплением (факториал, числа Фибоначчи).
- Работы с древовидными структурами.
Структура рекурсивных правил:
- Базовый случай — условие завершения рекурсии (например, факториал 0 равен 1).
- Шаг рекурсии — вызов предиката с уменьшенной задачей (например,
N-1для факториала).
3.2. Примеры рекурсивных предикатов
3.2.1. Факториал числа
Пояснение:
- При
N = 0возвращается 1.
- При
N > 0вычисляется факториал дляN-1, затем умножается наN.
Пример запроса:
3.2.2. Числа Фибоначчи
Важно: Эта реализация неэффективна для N > 20. Для оптимизации используйте аккумуляторы или мемоизацию (см. советы ниже).
Пример запроса:
3.2.3. Проверка списка на палиндром
Пример запроса:
3.2.4. Сумма элементов списка
Пример запроса:
3.3. Важные замечания
3.3.1. Условия остановки
- Всегда определяйте базовый случай, иначе рекурсия станет бесконечной.
- Проверяйте корректность входных данных (например,
N >= 0для факториала).
3.3.2. Порядок аргументов
- Первый аргумент — входной, второй — выходной (например,
factorial(N, Result)).
- Используйте
isдля арифметических операций:Result is N * R1.
3.3.3. Хвостовая рекурсия
Для оптимизации (например, в сумме списка) используйте аккумулятор:
Это предотвращает переполнение стека.
3.4. Типичные ошибки
Бесконечная рекурсия:
Некорректные арифметические операции:
Используйте
is, а не=:Неверный порядок условий:
Сначала проверяйте входные данные, затем выполняйте рекурсию:
3.5. Советы по отладке
Используйте
trace.для пошагового выполнения:Проверяйте промежуточные значения:
Самостоятельные задания к заданию №3
Задание 3.1: Рекурсия с аккумуляторами
Цель: Научиться оптимизировать рекурсию с использованием хвостового вызова.
Задачи:
- Перепишите предикат
sum_list/2(сумма элементов списка) с использованием аккумулятора.
- Реализуйте предикат
factorial_tail/2для вычисления факториала с хвостовой рекурсией.
Пример для factorial_tail:
Задание 3.2: Обработка вложенных структур
Цель: Работать с рекурсивными структурами данных.
Задачи:
- Напишите предикат
flatten/2, преобразующий вложенный список в плоский (например,[1, [2, [3]]→[1,2,3]).
- Реализуйте предикат
nested_sum/2, вычисляющий сумму всех чисел во вложенном списке.
Пример запроса:
Задание 3.3: Генерация последовательностей
Цель: Использовать рекурсию для создания списков.
Задачи:
- Реализуйте предикат
range/3, генерирующий список чисел отNдоM(например,range(2, 5, [2,3,4,5]).
- Напишите предикат
pow_sequence/3, создающий список степеней числа:pow_sequence(2, 3, [2,4,8]).
Подсказка:
Для range используйте рекурсию с аккумулятором:
Задание 3.4: Рекурсивная сортировка
Цель: Применить рекурсию для сортировки данных.
Задачи:
- Реализуйте алгоритм сортировки пузырьком для списка чисел.
- Напишите предикат
quick_sort/2, использующий алгоритм быстрой сортировки.
Пример для быстрой сортировки:
Задание 3.5: Обход графа
Цель: Использовать рекурсию для работы с графами.
Задачи:
- Определите предикат
path/3, проверяющий существование пути между двумя узлами в графе.
- Реализуйте поиск в глубину (DFS) для обхода графа.
Пример графа:
Задание 3.6: Отладка рекурсии
Цель: Находить и исправлять ошибки в рекурсивных предикатах.
Задачи:
Даны некорректные реализации
fib/2иis_palindrome/1. Найдите ошибки и исправьте их.
Объясните, почему следующий код приводит к бесконечной рекурсии:
Задание 3.7: Творческие задачи
Цель: Применить рекурсию для нестандартных задач.
Задачи:
- Напишите предикат
balanced_brackets/1, проверяющий баланс круглых скобок в строке (например,"(()())"— сбалансировано).
- Реализуйте генератор всех подмножеств списка (
subsets/2).
Пример для subsets:
Задание 3.8: Оптимизация рекурсии
Цель: Сравнить эффективность разных подходов.
Задачи:
- Реализуйте вычисление чисел Фибоначчи с использованием мемоизации (кэширования результатов).
- Измерьте время выполнения обычной и хвостовой рекурсии для
factorial(1000).
Подсказка:
Используйте assertz для сохранения промежуточных результатов:
Бонусное задание: Ханойские башни
Цель: Решить классическую задачу с использованием рекурсии.
Задача:
Напишите предикат hanoi/4, который выводит последовательность перемещений для решения головоломки «Ханойские башни» с N дисками.
Пример:
Задание № 4: Работа со списками
Цель: Изучить методы работы со списками в Prolog.
Теоретические сведения
Списки являются одной из основных структур данных в Prolog. Они представляются в виде [H|T], где H — голова списка, а T — хвост (подсписок).
Задания
- Реализовать предикат для поиска элемента в списке.
- Написать предикат для вычисления длины списка.
- Реализовать предикат для обращения списка.
- Написать предикат удаления элемента из списка.
Задание №5: Деревья в Prolog
Цель: Научиться представлять и обрабатывать деревья в логическом программировании.
Теоретические сведения
Деревья в Prolog представляются рекурсивными структурами, например, в виде node(Левое_поддерево, Значение, Правое_поддерево). Деревья используются для представления и обработки иерархических данных.
Задания
- Определить структуру бинарного дерева в Prolog.
- Реализовать предикат обхода дерева в глубину.
- Написать предикат нахождения максимального элемента в бинарном дереве.
- Реализовать предикат поиска элемента в дереве.
Задание №6: Поисковые алгоритмы в Prolog
Цель: Изучить основные алгоритмы поиска в логическом программировании.
Теоретические сведения
В логическом программировании используются алгоритмы поиска в ширину и глубину для обработки графов. Prolog позволяет элегантно реализовывать эти алгоритмы благодаря механизму унификации и рекурсии.
Задания
- Реализовать алгоритм поиска в ширину для графа.
- Написать алгоритм поиска в глубину.
- Реализовать алгоритм нахождения кратчайшего пути в графе (например, на основе алгоритма Дейкстры).
- Проверить работу алгоритмов на тестовых данных.