Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
progF_pos.doc
Скачиваний:
36
Добавлен:
11.05.2015
Размер:
1.51 Mб
Скачать

4. Определение функций

Дать имя и определить новую функцию можно с помощью функции DEFUN (define function). DEFUN вызывается так:

(DEFUN имя список_формальных_аргументов тело)

Пример:

(defun list2 (x y) (cons x (cons y nil)))

Передача параметров в Лиспе осуществляется в основном по значению. Параметры в Лиспе используются преимущественно лишь для передачи данных в функцию, а результаты возвращаются как значение функции, а не как значения параметров переданных по ссылке.

Форма - символьное выражение, значение которого может быть вычислено интерпретатором:

  • константы;

  • символы, которые используются в качестве переменных;

  • определения функций и вызовы функций;

  • специальные формы (SET, SETQ, SET, QUOTE, COND, IF и другие).

Разветвление вычислений: условное предложение COND. Это синтаксическая форма, позволяющая управлять вычислениями на основе определяемых предикатами условий. Структура условного предложения такова:

(cond (p1 a1)

(p2 a2)

..........

(pN aN))

Предикатами pi и результирующими выражениями ai могут быть произвольные формы. Значение предложения COND определяется следующим образом.

  1. Выражения pi , выполняющие роль предикатов, вычисляются последовательно слева направо (сверху вниз) до тех пор, пока не встретится выражение, значением которого не является NIL, т. е. логическим значением которого является истина.

  2. Вычисляется результирующее выражение, соответствующее этому предикату, и полученное значение возвращается в качестве значения всего предложения COND.

  1. Если истинного предиката нет, то значением COND является NIL.

Рекомендуется в качестве последнего предиката использовать символ T.

(defun sign (x)

(cond ((> x 0) ‘positive)

((< x 0) ‘negative))

(t ‘zero))

)

В условном предложении может отсутствовать результирующее выражение ai или на его месте может быть последовательность форм:

(cond (p1 a11)

............

(pi)

.......

(pk ak1 ak2 akN)

.........)

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

(IF условие то-форма иначе-форма)

эквивалентно

(COND (условие то-форма)

( T иначе-форма))

LET создает локальную связь. Вычисление вызова функции создает на время вычисления новые связи для формальных параметров функции. Новые связи внутри формы можно создавать и с помощью предложения LET. Эта структура (немного упрощенно) выглядит так:

(let ((m1 знач1 ) (m2 знач2 ) ... )

(форма1 форма2 ...)

)

Форма LET вычисляется так, что сначала локальные переменные m1, m2, ... из первого “аргумента” формы связываются (одновременно) с соответствующими значениями знач1, знач2, ... . Затем слева направо вычисляются значения форм форма1, форма2, ... . В качестве значения всего LET возвращается значение последней формы. Как и у функций, после окончания вычисления связи локальных переменных m1, m2, ... ликвидируются и любые изменения их значений не будут видны извне.

(setq x 2)

> x ==> 2

(let ((x 0))

(setq x 1))

==> 1

> x ==> 2

(let ((x 2) (y (* 3 x)))

(list x y))

===> unbound atom x

Примеры программ

; квалифицированные выражения и локальные функции

; неудачное определение

(defun f1 (x)

(+ (square (max x 4))

(if (<= x 1) 1 (square (max x 4)))

)

)

; вспомогательная функция

(defun g (a b)

(+ a (if (<= b 1) 1 a))

)

(defun f2 (x) (g (square (max 4 x)) x))

; использование квалифицированного выражения

(defun f3 (x)

(let

( (a (square (max 4 x))) )

(+ a (if (<= x 1) 1 a))

)

)

; использование локальной функции

(defun f4 (x)

(flet

( (a (y) (square (max 4 y))) )

(+ (a x) (if (<= x 1) 1 (a x)))

)

)

Определения форм FLET, LABELS

(flet ( <binding> ...) <expr>)

(labels (<binding> ...) <expr>)

где

<binding> - функциональные связи, каждая из которых имеет вид

(<sym> <farg> <body>)

<sym> - имя локальной функции

<farg> - список формальных параметров

<body> - тело локальной функции

<expr> - вычисляемое выражение формы, содержащее вызовы локальных функций.

Labels используется в рекурсивном случае.

Накапливающие параметры

Стандартное определение факториала (n! = 1*2*3*…*n):

(defun ! (n)

(if (= n 0) 1.0

(* n (! (1- n))))

)

При больших n стек будет переполнен.

В следующем определении используется метод накапливающего параметра. Определена локальная функция fac, у которой второй аргумент служит для накопления результата.

(defun ! (n)

(labels ((fac (x y)

(if (zerop x) y (fac (1- x) (* x y))))

)

(fac n 1.0))

)

Нахождение наибольшего общего делителя двух чисел

(defun gcd (n m)

(let ((r (rem n m)))

(if (zerop r) m (gcd m r))))

Вычисление суммы и произведения элементов списка

; 1 вариант

; программирование "в лоб"

(defun sumpr (x)

(if (null x) (list 0 1)

(list (+ (first x) (first (sumpr (rest x))))

(* (first x) (second (sumpr (rest x))))))

)

; 2 вариант

; использование let

(defun sumpr (x)

(if (null x) (list 0 1)

(let ((z (sumpr (rest x))))

(list (+ (first x) (first z))

(* (first x) (second z)))))

)

; 3 вариант

; еще одно использование let

(defun sumpr (x)

(if (null x) (list 0 1)

(let ((n (first x)) (z (sumpr (rest x))))

(list (+ n (first z))

(* n (second z)))))

)

; 4 вариант

; еще одно использование let

(defun sumpr (x)

(if (null x) (list 0 1)

(let ((n (first x)) (z (sumpr (rest x))))

(let ((a (first z)) (b (second z)))

(list (+ n a) (* n b)))))

)

; 5 вариант

; использование накапливающих параметров

(defun sumpr (x) (sp x 0 1))

(defun sp (x s p)

(if (null x) (list s p)

(sp (rest x) (+ (first x) s) (* (first x) p)))

)

; 6 вариант

; использование локальной функции

(defun sumpr (x)

(labels ((sp (y s p)

(if (null y) (list s p)

(sp (rest y) (+ s (first y)) (* p (first y))))))

(sp x 0 1))

)

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]