Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Рекурсия и цикл в программах на ЛиспеСодержание книги
Поиск на нашем сайте
В «чистом» функциональном программировании организация повторяющихся вычислений должна происходить лишь с помощью условных предложений и определения рекурсивных, вызывающих самих себя, функций. Рассмотрим в качестве примера функцию, просто определяемую через рекурсию, - факториал n!=1*2 * 3 *...* (n-1) * n = (n-1)! т n (0! = 1 по определению):
(defun! (n) (if(= п 0) 1 (* п (! (. п 1))))).
Имя функции - "!",ее аргументом является переменная n. Лямбда-выражение, определяющее функцию, представляет собой условную if-форму, которая в случае n=0 возвращает 1, а в противном случае вычисляет произведение n и результата вызова этой же функции! для аргумента n-1. Пример вызова этой функции:
(!5) Результат: 120.
В случае повторяющихся вычислений в Лиспе могут быть использованы не только рекурсивные функции, но и известные по процедурным языкам циклы. Самым общим циклическим предложением в Лиспе является DO, имеющее следующую форму:
(DO ((nepi знач! шаг1) (пер2 знач2 шаг 2)...) форма21 форма22...)
Вычисление предложения DO начинается с присваивания переменным пep1, пер2,... начальных значений знач1, знач2,... соответственно; потом вычисляется условие окончания и, если оно истинно, последовательно вычисляются формы форма1i, и значение последней возвращается как результат DO-предложения. В противном случае вычисляются формы форма2i из тела предложения DO, затем значения переменных пep1, пер2,... изменяются на величину шага шаг1, шаг2,... и все повторяется. Для примера с помощью предложения DO определим функцию expt, вычисляющую n-ю степень числа х (n - целое положительное):
(defun expt (х n) (do ((результат 1)); начальное значение ((= n 0) результат); условие окончания (setq результат (* результат х)) (setqn(^nl)))) Результат задания функции: EXPT. Пример вызова: (expt 2 3) Результат: 8. Итеративные (циклические) и рекурсивные программы теоретически одинаковы по своим вычислительным возможностям, однако свойства итеративных и рекурсивных вариантов программ могут существенно различаться. Рекурсивные программы более короткие и содержательные. Особенно полезно использовать рекурсию в тех случаях, когда решаемая задача и обрабатываемые данные по своей сути рекурсивны, например, при обработке списков, так как списки могут рекурсивно содержать подсписки, при работе с другими динамическими структурами, которые заранее не полностью известны. Рекурсивные процедуры играют важнейшую роль почти во всех программах, связанных с искусственным интеллектом.
ВВОД-ВЫВОД ДАННЫХ
До сих пор рассматривался ввод и вывод данных в лисповских программах через параметры функций и свободные переменные. Для организации диалога человека с программой в Лиспе существуют специальные функции READ и PRINT. Для вывода результатов можно использовать функцию PRINT. Это функция с одним аргументом, которая сначала вычисляет значение аргумента, а затем выводит это значение. Например:
(PRINT (* 2 2)) Результат: 4.
Перед выводом происходит переход на новую строку. Функция READ читает и возвращает выражение: (READ). Как только интерпретатор встречает такое предложение, вычисления приостанавливаются до тех пор, пока не будет введен какой-либо символ или целиком выражение. Аргументов у функции READ нет, ее использование построено на побочном эффекте, состоящем именно во вводе выражения. Прочитанное выражение можно сохранить для следующего использования и обработки, например, так:
(setq input (read));
прочитанное READ выражение присваивается переменной input. Лисповские операторы ввода-вывода очень гибки, их можно использовать в качестве аргументов других функций. Для более эстетичного оформления вывода можно использовать функции PRINC, печатающую строку без окаймляющих кавычек и со специальными символами, а также TERPRI, переводящую строку. Для форматного вывода (в соответствии с некоторым образом) существует функция FORMAT, обладающая гибкими возможностями, описанными в руководствах по языку Лисп. Помимо стандартных устройств ввода-вывода, может осуществляться обработка файлов на магнитных носителях, загружаться из файлов определения функций и т.д. ПРИМЕР ПРОГРАММИРОВАНИЯ НА ЛИСПЕ
Рассмотрим в качестве примера программирования на Лиспе менее элементарную классическую задачу, носящую название игры в «ханойские башни». Игра состоит в следующем. Используются три вертикальных стержня А, В, С и набор N дисков разного диаметра с отверстием посередине (так что их можно надевать на стержни). В начальном положении все диски надеты на стержень А по порядку убывания диаметров: внизу самый большой, над ним - поменьше и т.д., а наверху - самый маленький. Целью является перенос всех дисков со стержня А на стержень В по следующим правилам: 1) за один раз можно перенести только один диск; 2) больший по размеру диск нельзя положить на меньший; 3) третий стержень С можно использовать как вспомогательный. Алгоритм решения задачи можно представить в виде трех следующих рекурсивных подзадач: 1) перенести со стержня А N-1 дисков на вспомогательный стержень С; 5) перенести нижний диск со стержня А на стержень В; 6) перенести со стержня С N-1 дисков на стержень В. Программа состоит из трех последовательно определяемых функций «ханойские-башни», «перенос», «выведи» и имеет вид: Программа 130 (defun ханойские-башни (высота) (рrоgn (перенос "а "Ь "с высота) "готово)) ХАНОЙСКИЕ-БАШНИ (defun перенос (из в вспомогательный n) (cond ((= п 1); ветвь 2 (выведи из в) (t (перенос из; ветвь1 вспомогательный в (- n 1)) (выведи из в) (перенос вспомогательный; ветвь 3 в из (- п 1))))) ПЕРЕНОС (defun выведи (из в) (format t "~S -> ~S~%"из в)) ВЫВЕДИ
Вызов функции «ханойские башни» дает такое решение: (ханойские-башни 3) А->В А->С В->C А->В С->А С->В А->В ГОТОВО
Можно убедиться, что определенная нами функция дает правильное решение для произвольного числа дисков, однако время решения задачи с увеличением числа дисков быстро возрастает.
СВОЙСТВА СИМВОЛОВ
В Лиспе могут быть определены, так называемые, свойства символов. Список свойств имеет вид:
(имя_свойства1 значение1 имя_свойства2 значение2... имя_свойстваN значениеN).
Присваивание нового свойства или изменение значения существующего осуществляется с помощью функции PUTPROP (или просто PUT):
(PUTPROP символ свойство значение).
Выяснить значение свойства, связанного с символом, можно с помощью функции GET:
(GET символ свойство).
С использованием этой функции можно также присваивать свойства символам:
(SETF (GET символ свойство) значение).
Свойства символов глобальны Эта конструкция языка Лисп полезна во многих типичных случаях представления данных, в том числе семантических сетей, фреймов и объектов объектно-ориентированного программирования.
Контрольные вопросы и задания 1. В чем состоит основная идея функционального программирования? 2. Что называется символом в программировании на Лиспе? 3. Что такое атомы в программах на Лиспе? 4. Что такое список? 5. Охарактеризуйте примитивные функции языка Лисп. 6. Как можно связать с символом некоторое значение? Как поместить значение в ячейку памяти? 7. Приведите примеры 1-выражений в Лиспе. 8. Как можно определить функцию и дать ей имя для последующих вызовов в Лиспе? 9. Охарактеризуйте управляющие формы в Лиспе. 10. Какую роль играет в функциональном программировании рекурсия? 11. Запишите рекурсивные определения функции проверяющую наличие в списке некоторого заданного элемента, подсчитывающую число элементов в списке, соединяющую два списка (с использованием точечной нотации).
§9. ВВЕДЕНИЕ В ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ
ОСНОВНЫЕ ПОЛОЖЕНИЯ
Как уже отмечалось выше (п. 4.1), в настоящее время растет популярность методологий, ориентированных на данные. В первую очередь, это объектно-ориентированное программирование. Объектно-ориентированная методология проектирования программ основана на концепциях упрятывания информации и абстрактных типов данных. Такой подход рассматривает все такие ресурсы как данные, модули и системы в качестве объектов. Каждый объект содержит некоторую структуру данных (или тип данных), обрамленную набором процедур (методов), предназначенных для манипулирования этими данными. Используя эту методологию, программист может создать свой собственный абстрактный тип и отобразить проблемную область в эти созданные им абстракции вместо традиционного отображения проблемной области в предопределенные управляющие структуры и структуры данных языка программирования. Подобный подход является более естественным, чем методологии, ориентированные на обработку (на процесс), из-за возможности использовать в процессе программирования разнообразные виды абстракции типов данных. На этом пути программист может сконцентрироваться на проекте системы, не беспокоясь о деталях информационных объектов, используемых в системе. Основные шаги разработки программы, предусмотренные даннойметодологией: • определить проблему; • развить неформальную стратегию, представляющую общую последовательность шагов, удовлетворяющую требованиям к будущей программе; • формализовать стратегию • идентифицировать объекты иих атрибуты; • идентифицировать операции; • установить интерфейсы; • реализовать операции. Большинство современных языков и систем программирования развивается в направлении все большего использования объектной методологии в создании программ. Характерными примерами являются универсальные языки Паскаль, СИ и даже Бейсик, в современных версиях которых появились средства объектно-ориентированного программирования. Так, начиная с версии 5.5, Турбо-Паскаль охватывает метод проектирования программ на основе объектно-ориентированного программирования.
|
||||
Последнее изменение этой страницы: 2016-08-10; просмотров: 325; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.135.209.231 (0.009 с.) |