- •Функциональное и логическое программирование
- •Глава 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. Программирование на языке пролог
- •Общие сведения о языке Пролог. Язык Пролог как система, реализующая логический вывод в исчислении предикатов первого порядка.
- •Фразы Хорна как средство представления знаний.
- •Синтаксис языка Пролог.
- •Фразы, термы, факты, правила.
- •Константы:
- •Простейшая программа на Прологе
- •Выполнение запроса в Прологе.
- •Неудача запроса и возврат назад.
- •Декларативная и процедурная семантика Пролога.
- •Рекурсивные процедуры.
- •Списки.
- •Операторы.
- •Средства управления ходом выполнения программы. Предикат сократить (отсечение).
- •Отрицание как неудача запроса.
- •Встроенные предикаты.
- •Типы отношений.
- •Ограничения, обеспечивающие целостность отношений.
- •Свойства отношений.
- •Подходы к программированию на языке Пролог.
Функция get - возвращает значение свойства, связанного с символом:
(GET символ свойство )
При отсутствии свойства функция GET возвращает NIL в качестве ответа.
Пусть имя студент имеет следующий список свойств (имя Иван отчество Иванович фамилия Иванов):
(GET ‘студент ‘имя) => Иван
(GET ‘студент ‘группа) => NIL
Присваивание свойства или изменение значения существующего свойства осуществляется уже известными нам функциями:
(SETF (GET символ свойство) значение)
Например:
(SETF (GET ‘студент ’группа) ’КИО8-15) => КИО8-15
(GET ‘студент ’группа) => КИО8-15
Псевдофункция remprop удаляет свойство и его значение:
(REMPROP символ свойство)
Эта функция возвращает в качестве значения имя удаляемого свойства. Если удаляемого свойства нет, то возвращается NIL:
(REMPROP ‘студент ’группа) => группа
(GET ‘студент ’группа) => NIL
(REMPROP ‘студент ’ср_бал) => NIL
Для просмотра всего списка свойств используют функцию SYMBOL-PLIST. Значением функции является весь список свойств.
(SYMBOL-PLIST символ)
Пример:
(SYMBOL-PLIST ‘студент) => (имя Иван отчество Иванович фамилия Иванов)
Свойства символов независимо от их значений доступны из всех контекстов до тех пор, пока не будут явно изменены или удалены. Изменение значения символа не влияет на значения свойств. Свойства символа передаются другому символу с помощью функции SETQ:
(SETF (get 'st 'sv1) '1) => 1
(GET 'st 'sv1) => 1
(SETQ st1 'st) => st
(GET st1 'sv1) => 1
Вызов интерпретатора eval вычисляет значение выражения.
Интерпретатор ЛИСПа называется EVAL. Его можно так же, как и другие функции вызывать из программы.
Вызов интерпретатора может, например, снять эффект блокировки вычисления или позволяет выполнить двойное вычисление.
QUOTE и EVAL действуют в противоположных направлениях и аннулируют друг друга. EVAL – универсальная функция ЛИСПа, вычисляющая любое правильно составленное s-выражение.
Эта функция определяет семантику лисповских форм, т.е. определяет, какие символы и формы совместно с чем и что означают и какие выражения имеют значения. Семантика ЛИСПа легко определяется на самом ЛИСПе. Большая часть системных программ в ЛИСП-системах написана на ЛИСПе, и пользователь легко может изменить систему в зависимости от своих потребностей. Транслятор также целиком написан на ЛИСПе.
Примеры:
(EVAL (QUOTE (+ 2 3))) => 5
(SETQ x '(a b c)) => (a b c)
'x => x
x => (a b c)
(EVAL 'x) => (a b c)
(EVAL x) => error: unbound function – a
(SETQ x '(+ 2 3)) => (+ 2 3)
x => (+ 2 3)
(EVAL 'x) => (+ 2 3)
(EVAL x) => 5
Ввод и вывод.
До сих пор ввод и вывод данных осуществлялись нами в режиме интерпретатора. Интерпретатор читал вводимое выражение, вычислял его значение и возвращал пользователю. Сами формы и функции не содержали ничего, связанного с вводом или выводом.
Если не использовать команду ввода, то данные можно передавать функции только через параметры и свободные переменные. Результат без использования вывода можно получить лишь через конечное значение выражения. Однако часто возникает необходимость вводить исходные данные и выдавать сообщения во время вычисления функции.
Для выполнения ввода существует функция:
(READ)
Как только интерпретатор встречает вызов этой функции, вычисления приостанавливаются, пока пользователь не введет выражение.
В качестве результата функция возвращает само это выражение, т.е. непосредственно ввод является побочным эффектом действия функции.
Если прочитанное значение необходимо сохранить для дальнейшего использования, то вызов (READ) должен быть аргументом какой-нибудь формы, например, присваивания, которая свяжет полученное выражение:
(setq a (read))
Форма, вызывающая интерпретатор (EVAL), и функция (READ) совместно с другими функциями позволяют читать выражения, внешние по отношению к программе. Из них можно строить новые Лисповские выражения или целые программы. Построенные структуры можно вычислить, передав их непосредственно интерпретатору:
Пример 1.
(eval (list (read) (read) (read)))
cons 23 '(1 2 3) => (23 1 2 3)
Пример 2.
(setq a 34)
(eval (list (read) (read) (read)))
/ a 2 => 17
Для выполнения вывода в Лиспе существует функция:
(PRINT арг. )
Это функция с одним аргументом, которая сначала вычисляет значение аргумента, а затем выводит это значение.
Перед выводом аргумента происходит переход на новую строку, а после вывода аргумента выводится пробел.
Значением функции является значение ее аргумента, побочным эффектом – печать этого значения.
Операторы ввода-вывода могут быть аргументами других функций:
(+ (print 2) 3)
=> 2
=> 5
Функции
(PRIN1 арг.)
(PRINC арг.)
позволяют выводить данные без перехода на новую строку. PRINC осуществляет символьный вывод. Различие: PRIN1 выводит строку в кавычках, а PRINC без кавычек.
(progn (princ "(((") (prin1 123) (princ ")))"))
=> (((123)))
=> ")))"
Функция (TERPRI) осуществляет перевод строки.
Для форматированного вывода предназначена функция:
(FORMAT поток образец &REST аргументы).
Поток – задает файл или устройство, куда осуществляется вывод;
- Т – вывод на экран.
- при выводе в файл потоком является поток вывода, представляющий этот файл.
NIL – у такой формы есть лишь значение (строка, построенная по образцу с помощью управляющих кодов и аргументов) и нет побочного эффекта, связанного с выводом.
Образец – управляющая строка, которая содержит управляющие коды. Перед управляющим кодом ставится знак ~ (тильда).
~% - переводит строку
~S – выводит функцией PRIN1 значение очередного аргумента
~А – выводит функцией PRINС значение очередного аргумента
~nТ – начинает вывод с колонки n. Если ее уже достигли, то выводится пробел.
~~ - выводит сам знак тильды.
Аргументы ставятся в соответствие управляющим кодам строки:
Если управляющие коды и соответствующие им аргументы не используются, то строка выводится так же, как и функцией PRINC, в качестве значения возвращается NIL.
Примеры форматированного вывода.
Пример 1.
(format t "111~%222~%333")
111 печать
222 печать
333 печать
NIL результат
Пример 2.
(format nil "otvet - ~S" (+ 2 3)) печати нет
= > "otvet - 5" значением является строка
Пример 3.
(setq x 2) => 2
(setq y 3) => 3
(format t "~S + ~S = ~S~%" x y (+ x y))
2 + 3 = 5 печать
NIL результат
Пример 4.
(defun tabl (sp)
(format t "~%FIO~10Ttelefon")
(do ((x sp (rest x)))
((null x) (terpri))
(format t "~%~A~10T~A" (caar x) (cadar x))))
(tabl '((IVANOV 12-34-12)(PETROV 43-23-65)(SIDOROV 32-12-65)))
FIO telefon
IVANOV 12-34-12
PETROV 43-23-65
SIDOROV 32-12-65
