ЗАДАНИЯ И МЕТОДИЧЕСКИЕ УКАЗАНИЯ
к лабораторной работе
по дисциплине «Функциональное программирование»
для студентов 4 курса
дневного отделения факультета АВТ,
обучающихся по направлению
09.04.01 Программная инженерия

Лабораторная работа №1.
Основы функционального программирования
(4 часа)

Цель работы:

Приобретение практических навыков написания и отладки программ на языке функционального программирования Lisp.

Задание:

В соответствии с вариантом написать программу на языке функционального программирования Lisp.

Вариант 1:

-  Определить рекурсивную функцию, возвращающую значение n-го члена ряда Фибоначчи: f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2).

-  Определить функцию, вычисляющую, сколько всего атомов в списке (списочной структуре).

Вариант 2:

-  Определить рекурсивную функцию для удаления последнего элемента списка.

-  Определить функцию, вычисляющую глубину списка (самой глубокой ветви).

Вариант 3:

-  Определить рекурсивную функцию, возвращающую произведение двух целых положительных чисел (использовать суммирование).

-  Определить функцию, возвращающую предпоследний элемент списка.

Вариант 4:

-  Определить рекурсивную функцию, возвращающую последний элемент списка.

-  Определить функцию, подсчитывающую число элементов списка без какого-либо указываемого элемента.

Вариант 5:

-  Определить рекурсивную функцию, возвращающую значение суммы ряда целых четных чисел от 2 до n.

-  Определить функцию (first_elem x y), которая возвращает первый элемент, входящий в оба списка x и y, в противном случае nil.

НЕ нашли? Не то? Что вы ищете?

Вариант 6:

-  Определить рекурсивную функцию, возвращающую значение n-го члена ряда Фибоначчи: f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2).

-  Определить функцию, вычисляющую, сколько всего атомов в списке (списочной структуре).

Вариант 7:

-  Определить рекурсивную функцию для удаления последнего элемента списка.

-  Определить функцию, вычисляющую глубину списка (самой глубокой ветви).

Вариант 8:

-  Определить рекурсивную функцию, возвращающую произведение двух целых положительных чисел (использовать суммирование).

-  Определить функцию, возвращающую предпоследний элемент списка.

Вариант 9:

-  Определить рекурсивную функцию, возвращающую последний элемент списка.

-  Определить функцию, подсчитывающую число элементов списка без какого-либо указываемого элемента.

Вариант 10:

-  Определить рекурсивную функцию, возвращающую значение суммы ряда целых четных чисел от 2 до n.

-  Определить функцию (first_elem x y), которая возвращает первый элемент, входящий в оба списка x и y, в противном случае nil.

Содержание отчета (отчет в электронном виде):

-  титульный лист (образец можно скачать по адресу http://ermak. cs. nstu. ru/funcprog/fp_labwork_title_page. doc);

-  цель работы;

-  задание;

-  исходные тексты программ;

-  выводы по работе.

Теоретические сведения

Базовые функции

В Lisp’е существует пять основных функций, называемых базовыми:

-  (car list) — отделяет голову списка (первый элемент списка);

-  (cdr list) — отделяет хвост списка (все элементы, кроме первого, представленные в виде списка);

-  (cons head tail) — соединяет элемент и список в новый список, где присоединенный элемент становится головой нового списка;

-  (equal object1 object2) — проверяет объекты на равенство;

-  (atom object) — проверяет, является ли объект атомом.

Так как функции equal и atom возвращают значения nil или t, их можно назвать базовыми предикатами.

Рассмотрим примеры для перечисленных функций:

> (car ‘(one two three))

ONE

> (car ‘(one))

ONE

> (car ‘())

NIL

> (cdr ‘(first second third))

(SECOND THIRD)

> (cdr ‘(first))

NIL

> (cdr ‘())

NIL

> (cons 1 ‘(2 3))

(1 2 3)

> (cons 1 nil)

(1)

> (cons nil nil)

(NIL)

> (equal ‘(1 2 3) ‘(1 2 3))

T

> (equal ‘(1 2 3) ‘(3 2 1))

NIL

> (equal ‘one ‘two)

NIL

> (atom ‘one)

T

> (atom 1)

T

> (atom (1))

NIL

Предложения prog1, prog2, progN

(progX form1 form2 … formN)

Назначение: выполнение последовательных вычислений.

Пример:

>(progn (setq x 2) (setq y (* 3 x)))

6

Предложение cond

(cond (predicate1 form1) (predicate2 form2) … (predicateN formN))

Назначение: выполнение ветвления.

Пример: функция, определяющая тип выражения (пустой список, атом или список).

>(defun deftype(arg)

(cond ((null arg) ‘empty) ((atom arg) ‘atom) (t ‘list)))

DEFTYPE

>(deftype ‘(a b c))

LIST

>(deftype (atom ‘(a t o m)))

EMPTY

Предложение if

(if (condition) thenform elseform)

Назначение: выполнение ветвления.

Пример:

>(setq x ‘(a b c))

(A B C)

>(if (atom x) ‘atom ‘list)

LIST

Предложение do

(do ((var1 value1) (var1 value1) … (var1 value1))

(endcondition form11 form12)

form 21 form 22)

Назначение: выполнение циклических вычислений.

Пример: вычисление суммы целых чисел от n до 0.

>(defun count (n)

(do ((result n)) ;;начальное значение

((= n 0) result) ;;условие окончания цикла

(setq n (- n 1))

(setq result (+ result n))

)

)

COUNT

>(count 5)

15

Простая рекурсия

Функция является рекурсивной, если в ее определении содержится вызов этой же функции. Рекурсия является простой, если вызов функции встречается в некоторой ветви лишь один раз. Простой рекурсии в процедурном программировании соответствует обыкновенный цикл.

Пример: построение копии списка.

>(defun listcopy (list)

(cond ((null list) nil) ;;граничное условие

(t (cons (car list) (listcopy (cdr list)))))) ;;рекурсия

LISTCOPY

>(listcopy ‘(a b c))

(A B C)

Трассировка программы

Для отладки программы можно использовать возможности трассировки. Трассировка позволяет проследить процесс нахождения решения.

Для того, чтобы включить трассировку, можно воспользоваться следующей директивой:

(trace function)

Назначение: включает режим трассировки.

Пример:

>(trace listcopy)

(LISTCOPY)

>(listcopy '(a b))

Entering: LISTCOPY, Argument list: ((A B))

Entering: LISTCOPY, Argument list: ((B))

Entering: LISTCOPY, Argument list: (NIL)

Exiting: LISTCOPY, Value: NIL

Exiting: LISTCOPY, Value: (B)

Exiting: LISTCOPY, Value: (A B)

(A B)

(untrace function)

Назначение: отключает режим трассировки.

Пример:

>(untrace listcopy)

NIL