- •Функциональное и логическое программирование
- •Глава 1. Классификация языков и стилей программирования 3
- •Глава 2. Программирование на языКе лисп 16
- •Глава 3. Программирование на языке пролог 89
- •Глава 1. Классификация языков и стилей программирования
- •Основные парадигмы программирования
- •Процедурное (императивное, директивное) программирование.
- •Объектно-ориентированное программирование.
- •Декларативное программирование
- •Логическое программирование.
- •Функциональное программирование.
- •Классификация языков программирования
- •Функциональные языки
- •Логические языки
- •Глава 2. Программирование на языКе лисп
- •История создания языка Лисп
- •Диалекты языка Лисп
- •Лисп-машины
- •Область применения языка Лисп
- •Особенности языка Лисп Одинаковая форма данных и программ
- •Хранение данных, не зависящее от места
- •Автоматическое и динамическое управление памятью
- •Функциональная направленность
- •Динамическая проверка типов
- •Интерпретирующий и компилирующий режимы работы;
- •Пошаговое программирование
- •Единый системный и прикладной язык программирования
- •Основы языка Лисп
- •Понятие функции.
- •Quote блокирует вычисления
- •Базовые функции языка.
- •Функция car возвращает в качестве значения первый элемент списка.
- •Функция cdr - возвращает в качестве значения хвостовую часть списка, т. Е. Список, получаемый из исходного списка после удаления из него головного элемента:
- •Функция cons включает новый элемент в начало списка:
- •Предикат equal проверяет идентичность записей:
- •Предикат equalp проверяет наиболее общее логическое равенство:
- •Другие простейшие встроенные функции Лиспа. Функция null проверяет, является ли аргумент пустым списком:
- •Комбинации вызовов car и cdr позволяют получить любой элемент списка:
- •Наиболее общая функция, выделяющая n-й элемент списка (при этом индексация начинается с 0):
- •Функция last позволяет выделить последний элемент списка:
- •Функция list - создает список из элементов:
- •Функция setq – невычисляющее присваивание:
- •Функция setf - обобщенная функция присваивания:
- •Функции, обладающие побочным эффектом, называются псевдофункциями.
- •С символом можно связать именованные свойства:
- •Функция get - возвращает значение свойства, связанного с символом:
- •Псевдофункция remprop удаляет свойство и его значение:
- •Вызов интерпретатора eval вычисляет значение выражения.
- •Ввод и вывод.
- •Использование файлов.
- •Определение функций
- •Задание параметров в лямбда-списке.
- •Передача параметров и область их действия.
- •Вычисления в лисПе.
- •Предложение let создает локальную связь внутри формы:
- •Последовательные вычисления.
- •Разветвление вычислений.
- •Циклические вычисления.
- •Передача управления.
- •Другие циклические структуры.
- •Динамическое управление из другого контекста
- •Внутреннее представление списков
- •Функциональное программирование Рекурсия. Различные виды рекурсии.
- •Функции более высокого порядка.
- •Применяющие функционалы.
- •Отображающие функционалы.
- •Макросы
- •Типы данных
- •Основные типы данных:
- •Глава 3. Программирование на языке пролог
- •Общие сведения о языке Пролог. Язык Пролог как система, реализующая логический вывод в исчислении предикатов первого порядка.
- •Фразы Хорна как средство представления знаний.
- •Синтаксис языка Пролог.
- •Фразы, термы, факты, правила.
- •Константы:
- •Простейшая программа на Прологе
- •Выполнение запроса в Прологе.
- •Неудача запроса и возврат назад.
- •Декларативная и процедурная семантика Пролога.
- •Рекурсивные процедуры.
- •Списки.
- •Операторы.
- •Средства управления ходом выполнения программы. Предикат сократить (отсечение).
- •Отрицание как неудача запроса.
- •Встроенные предикаты.
- •Типы отношений.
- •Ограничения, обеспечивающие целостность отношений.
- •Свойства отношений.
- •Подходы к программированию на языке Пролог.
Выполнение запроса в Прологе.
Работу интерпретатора языка Пролог можно трактовать как рекурсивный циклический процесс унификации (согласования) и вычисления подцелей.
Действия интерпретатора инициируются запросом. В ходе выполнения этих действий интерпретатор опустится в структуру программы настолько глубоко, насколько это будет необходимо для поиска фактов, требующихся для определения истинностного значения запроса. Затем интерпретатор вернется в исходное состояние, доказав или оказавшись не в состоянии доказать истинность запроса.
После ввода пользователем запроса, запрос активируется, т.е. помещается в вершину стека активных запросов. Интерпретатор приступает к анализу фраз текущей программы в поисках первой фразы, заголовок которой согласуется с запросом. Чтобы запрос согласовался с заголовком фразы, необходимо совпадение у них имени предиката и количества аргументов, причем все аргументы должны согласоваться.
Правила согласования термов:
переменная согласуется с константой или структурой. В результате эта переменная становится конкретизированной, т.е. принимает значение этой константы или структуры;
переменная согласуется с переменной, при этом они обе становятся одной и той же переменной (т.е. интерпретатор дает им одно и то же внутреннее имя);
анонимная переменная "_" согласуется с любым объектом;
константа согласуется с константой, если они идентичны;
структура согласуется с другой структурой, если они имеют одинаковые функторы, а аргументы поддаются унификации.
После того, как фраза, согласующаяся с запросом, будет обнаружена, она активируется. При этом каждая подцель, входящая в тело фразы, обрабатывается также, как и исходный запрос. Если тело согласующейся фразы является пустым, т.е. она представляет собой факт, то запрос сразу же оказывается успешным.
Если интерпретатор не может найти фразу согласующуюся с целью, то он возвратится назад. Он возвращается к последней успешной подцели, ликвидирует конкретизацию любых переменных, явившуюся результатом успешной обработки этой подцели, и приступает к поиску в множестве фраз текущей программы заголовка другой фразы, которая согласуется с данной подцелью.
При успешном выполнении запроса пользователя интерпретатор выводит на терминал значения всех тех переменных, входящих в состав запроса, которые были конкретизированы в результате процесса обработки, или слово «да», если переменные в запросе отсутствовали.
Если пользователь введет символ «;» после того, как интерпретатор нашел ответ, то это будет эквивалентно отказу от полученного ответа. Интерпретатор вернется назад и попытается найти иной ответ. Покажем процесс выполнения запроса на примере. Допустим, созданы базы данных «отец», «брат» и правило «дядя»:
отец (коля, миша).
отец(коля, саша).
брат(миша, саша).
брат(вася, коля).
дядя(А, В):-
брат(А, С),
отец(С, В).
Рассмотрим запрос «дядя» к программе:
?-дядя(вася, X).
Как только в стеке появился запрос, интерпретатор приступает к поиску множества фраз с тем же самым именем предиката и с тем же количеством аргументов, что и у запроса. Если таких фраз нет, то запрос неудачен. Интерпретатор анализирует первую фразу множества фраз «дядя» и пытается согласовать каждый аргумент запроса с соответствующим аргументом этой фразы. В нашем случае запрос «дядя» успешно согласуется с заголовком правила «дядя». В результате конкретизируется переменная А, которая получает значение «вася», а В и X становятся одной и той же неконкретизированной переменной. После того, как переменная, расположенная в заголовке правила, будет согласована с другим термом, результат согласования распространяется на каждый случай использования этой переменной в правиле.
Состояние интерпретатора:
активные запросы фразы программы
?-дядя(вася, X). дядя(вася, X):-
брат(вася, С),
отец(С, X).
После унификации запроса с заголовком фразы интерпретатор переходит к телу фразы. Если тело фразы пустое, т.е. фраза является фактом, то запрос сразу же является успешным. Если тело фразы не пустое, то интерпретатор помещает в стек запросов каждую подцель, входящую в тело, и, в свою очередь, обрабатывает ее. Если все подцели из тела фразы будут успешно обработаны, то и весь исходный запрос будет успешным.
Тело правила «дядя» состоит из двух подцелей «брат (вася, С)» и «отец (С, X)». Первая подцель «брат (вася, С)» помещается в стек запросов:
активные запросы фразы программы
?-дядя(вася, X). дядя(вася, X):-
брат(вася, С),
отец(С, X).
?- брат (вася, С).
Теперь новый запрос «брат (вася, С)» является активным запросом. Исходный запрос дядя (вася, X) однако все еще находится в стеке в ожидании обработки тела правила «дядя». Запрос «брат» теперь указывает на начало множества фраз «брат».Если попытка согласования запроса с заголовком фразы закончится неудачей, то интерпретатор перейдет к анализу следующей фразы соответствующего множества. Этот процесс будет продолжаться до тех пор, пока не обнаружится фраза, которую можно будет унифицировать с запросом. Если интерпретатор не найдет такую фразу, то запрос завершится неудачей.
В нашем случае интерпретатор предпринимает попытку согласовать подцель «брат (вася, С)» с фразой «брат (миша, саша)». Эта попытка заканчивается неудачей, т.к. «вася» не согласуется с «миша». Затем интерпретатор переходит к анализу следующей фразы «брат(вася, коля)». В данном случае запрос согласуется с фразой, переменная С конкретизируется, получает значение «коля», которое будет использоваться при каждом употреблении переменной С в правиле «дядя».
Состояние интерпретатора:
активные запросы фразы программы
?-дядя(вася, X). - указывет на - дядя(вася, X):-
брат(вася, коля),
отец(коля, X).
?- брат (вася, коля). - указывет на - брат(вася, коля).
Фраза «брат (вася, коля)» является фактом, у нее пустое тело, поэтому подцель «брат» сразу же оказывается успешной. Теперь интерпретатор помещает в вершину стека вторую подцель правила дядя - «отец (коля, X).»:
активные запросы фразы программы
?-дядя(вася, X). - указывет на - дядя(вася, X):-
брат(вася, коля),
отец(коля, X).
?- брат(вася, коля). - указывет на - брат(вася, коля).
?- отец (коля, X). - указывет на - отец (коля, миша).
отец (коля, саша).
Интерпретатор пытается согласовать подцель «отец (коля, X).» с фразой «отец (коля, миша)». Эта попытка приводит к успеху, в результате чего конкретизируется переменная X, которая получает значение «миша».
Состояние интерпретатора:
активные запросы фразы программы
?-дядя(вася, миша). - указывет на - дядя(вася, миша):-
брат(вася, коля),
отец(коля, миша).
?- брат(вася, коля). - указывет на - брат(вася, коля).
?- отец(коля, миша). - указывет на - отец(коля, миша).
отец(коля, саша).
Фраза «отец(коля, миша).» является фактом, поэтому запрос «отец» сразу же оказывается успешным. Больше подцелей в теле правила «дядя» нет, следовательно, и исходный запрос «дядя» будет успешным. Интерпретатор выводит значение переменной X=миша. При этом весь стек активных запросов сохраняется.
