Автор работы: Пользователь скрыл имя, 19 Февраля 2011 в 15:30, лабораторная работа
Цель: Ознакомиться со средой MuLisp. Изучить базовые функции Лиспа, символы и их свойства, а также средства для работы с числами. 
        
1.Основные положения программирования на Лиспе.
2.Загрузка системы, системный редактор.
3.Базовые функции языка. Символы, свойства символов.
4.Средства языка для работы с числами.
5.Задание к лабораторной работе.
6.Вопросы.
                              
                              
                              
                              
(T (PRINC «ошибка ввода»))))
7. Вопросы.
1. Для чего используется предложение LET?
2. В чем его отличие от предложения LET*?
3. Чем различаются функции COND и IF?
4. Каковы возвращаемые ими значения?
5. Чем различаются функции PROG1 и PROGN?
       6. Почему не желательно использовать 
операторы передачи управления? Чем 
их можно заменить? 
Лабораторная работа №4.
Тема: Рекурсия в Лиспе. Функционалы и макросы.
Цель: Изучить основы программирования с применением рекурсии. Научиться работать с функционалами и макросами.
1. Рекурсия. Различные формы рекурсии.
2. Применяющие функционалы.
3. Отображающие функционалы.
4. Макросы.
5. Задание к лабораторной работе.
       6. 
Вопросы. 
1. Рекурсия. Различные формы рекурсии.
Основная идея рекурсивного определения заключается в том, что функцию можно с помощью рекуррентных формул свести к некоторым начальным значениям, к ранее определенным функциям или к самой определяемой функции, но с более «простыми» аргументами. Вычисление такой функции заканчивается в тот момент, когда оно сводится к известным начальным значениям.
Рекурсивная процедура, во-первых содержит всегда по крайней мере одну терминальную ветвь и условие окончания. Во-вторых, когда процедура доходит до рекурсивной ветви, то функционирующий процесс приостанавливается, и новый такой же процесс запускается сначала, но уже на новом уровне. Прерванный процесс каким-нибудь образом запоминается. Он будет ждать и начнет исполняться лишь после окончания нового процесса. В свою очередь, новый процесс может приостановиться, ожидать и т. д.
Будем говорить о рекурсии по значению и рекурсии по аргументам. В первом случае вызов является выражением, определяющим результат функции. Во втором - в качестве результата функции возвращается значение некоторой другой функции и рекурсивный вызов участвует в вычислении аргументов этой функции. Аргументом рекурсивного вызова может быть вновь рекурсивный вызов и таких вызовов может быть много.
Рассмотрим следующие формы рекурсии:
Рекурсия называется простой, если вызов функции встречается в некоторой ветви лишь один раз. Простой рекурсии в процедурном программировании соответствует обыкновенный цикл.
       Для 
примера напишем функцию вычисления чисел 
Фибоначчи (F(1)=1; F(2)=1; 
F(n)=F(n-1)+F(n-2) при n>2): 
(DEFUN FIB (N)
(IF (> N 0)
(IF (OR N=1 N=2) 1
(+ (FIB (- N 1)) (FIB (- N 2))))
‘ОШИБКА_ВВОДА))
Рекурсию называют параллельной, если она встречается одновременно в нескольких аргументах функции:
(DEFUN f ...
...(g ... (f ...) (f ...) ...)
...)
Рассмотрим использование параллельной рекурсии на примере преобразования списочной структуры в одноуровневый список:
(DEFUN PREOBR (L)
(COND
                              
                              
                              
                              
                              
Рекурсия является взаимной между двумя и более функциями, если они вызывают друг друга:
(DEFUN f ...
...(g ...) ...)
(DEFUN g ...
                  
...(f ...) ...) 
       Для 
примера напишем функцию обращения или 
зеркального отражения в виде двух взаимно 
рекурсивных функций следующим образом: 
(DEFUN obr (l)
(COND ((ATOM l) l)
(T (per l nil))))
(DEFUN per (l res)
(COND ((NULL l) res)
(T (per (CDR l)
                              
2. Применяющие функционалы.
Функции, которые позволяют вызывать другие функции, т. е. применять функциональный аргумент к его параметрам называют применяющими функционалами. Они дают возможность интерпретировать и преобразовывать данные в программу и применять ее в вычислениях.
APPLY
APPLY является функцией двух аргументов, из которых первый аргумент представляет собой функцию, которая применяется к элементам списка, составляющим второй аргумент функции APPLY:
       (APPLY fn 
список) 
_(SETQ a ‘+) р +
_(APPLY a ‘(1 2 3)) р 6
       _(APPLY 
‘+ ‘(4 5 6)) р 15 
FUNCALL.
Функционал FUNCALL по своему действию аналогичен APPLY, но аргументы для вызываемой он принимает не списком, а по отдельности:
       (FUNCALL fn x1 x2 
... xn) 
       _(FUNCALL ‘+ 4 5 6) р 15 
       FUNCALL и APPLY позволяют задавать вычисления 
(функцию) произвольной формой, например, 
как в вызове функции, или символом, значением 
которого является функциональный объект. 
Таким образом появляется возможность 
использовать синонимы имени функции. 
С другой стороны, имя функции можно использовать 
как обыкновенную переменную, например 
для хранения другой функции (имени или 
лямбда-выражения), и эти два смысла (значение 
и определение) не будут мешать друг другу: 
_(SETQ list ‘+) р +
_(FUNCALL list 1 2) р 3
       _(LIST 
1 2) р 
(1 2) 
3. Отображающие функционалы.
Отображающие или MAP-функционалы являются функциями, которые являются функциями, которые некоторым образом отображают список (последовательность) в новую последовательность или порождают побочный эффект, связанный с этой последовательностью. Каждая из них имеет более двух аргументов, значением первого должно быть имя определенной ранее или базовой функции, или лямбда-выражение, вызываемое MAP-функцией итерационно, а остальные аргументы служат для задания аргументов на каждой итерации. Естественно, что количество аргументов в обращении к MAP-функции должно быть согласовано с предусмотренным количеством аргументов у аргумента-функции. Различие между всеми MAP-функциями состоит в правилах формирования возвращаемого значения и механизме выбора аргументов итерирующей функции на каждом шаге.
Рассмотрим основные типы MAP-функций.
Значение этой функции вычисляется путем применения функции fn к последовательным элементам xi списка, являющегося вторым аргументом функции. Например в случае одного списка получается следующее выражение:
(MAPCAR fn ‘(x1 x2 ... xn))
       В 
качестве значения функционала возвращается 
список, построенный из результатов вызовов 
функционального аргумента MAPCAR. 
_(MAPCAR ‘LISTP ‘((f) h k (i u)) р (T NIL NIL T)
_(SETQ x ‘(a b c)) р (a b c)
_(MAPCAR ‘CONS x ‘(1 2 3)) р ((a . 1) (b . 2) (c . 3))
       MAPLIST действует подобно MAPCAR, 
но действия осуществляет не над элементами 
списка, а над последовательными CDR этого 
списка. 
_(MAPLIST ‘LIST ‘((f) h k (i u)) р (T T T T)
       _(MAPLIST 
‘CONS ‘(a b c) ‘(1 2 3)) р (((a b c) 1 2 3) ((b c) 2 3) ((c ) 3)) 
Функционалы MAPCAR и MAPLIST используются для программирования циклов специального вида и в определении других функций, поскольку с их помощью можно сократить запись повторяющихся вычислений.
       Функции MAPCAN 
и MAPCON 
являются аналогами функций MAPCAR и MAPLIST. Отличие состоит в том, 
что MAPCAN 
и MAPCON 
не строят, используя LIST, новый список из результатов, 
а объединяют списки, являющиеся результатами, 
в один список. 
4. Макросы.
Программное формирование выражений наиболее естественно осуществляется с помощью макросов. Макросы дают возможность писать компактные, ориентированные на задачу программы, которые автоматически преобразуются в более сложный, но более близкий машине эффективный лисповский код. При наличии макросредств некоторые функции в языке могут быть определены в виде макрофункций. Такое определение фактически задает закон предварительного построения тела функции непосредственно перед фазой интерпретации.