Основы функционального программирования

Функции


Ситуация, когда атом обозначает функцию, реализационно подобна той, в которой атом обозначает аргумент. Если функция рекурсивна, то ей надо дать имя. Теоретически это делается с помощью формы LABEL, которая связывает название с определением функции в ассоциативном списке (а-списке). Название связано с определением функции точно так же, как переменная связана со своим значением. На практике LABEL используется редко. Удобнее связывать название с определением другим способом. Это делается путем размещения определения функции в списке свойств атома (р-список), символизирующего ее название. Выполняет данную операцию псевдо-функция DEFUN, описанная в начале этой лекции. Когда APPLY интерпретирует функцию, представленную атомом, она исследует р-список до поиска в а-списке. Таким образом, DEFUN будет опережать LABEL.

Тот факт, что большинство функций — константы, определенные программистом, а не переменные, изменяемые программой, вызван отнюдь не каким-либо недостатком функционального программирования. Напротив, он указывает на потенциал подхода, который мы не научились использовать лучшим образом. (Работы по теории компиляции, оптимизации и верификации программ, смешанным вычислениям, суперпрограммированию и т.п. активно используют средства функционального программирования.)

Системы функционального программирования обеспечивают возможность манипулирования функциональными переменными так же, как и обычными. Но организуется это с помощью ряда специальных функций, осуществляющих переход от символов, изображающих функции, к функциональным объектам, представленным этими символами. Такой переход может быть реализован в рамках любого языка программирования, но на Лиспе он выглядит естественно и поддерживается в любой Лисп-системе. Рассмотрим средства Clisp, обеспечивающие структурирование функциональных объектов.

Labels — позволяет из списка определений функций формировать контекст, в котором вычисляются выражения.

Flet — специальная функция, позволяющая вводить локальные нерекурсивные функции.


defun — позволяет вводить новые определения на текущем уровне.

(labels ( (INTERSECTION (x y)

(let* ( (N-X (null x)) (MEM-CAR (member (car x) y)) (INT #'intersection) ) ; конец списка локальных выраженийlet*

(flet ((f-tail (fn sx sy) (apply fn (list (cdr sx) sy)) ) (cons-f-tail (fn sx sy) (cons (car sx) (apply fn (list (cdr sx) sy)) )) ) ; конец списка нерекурсивных функций flet

(COND (N-X NIL) ; выражение, использующее (MEM-CAR (cons-f-tail INT x y) ) ; локальные определения функций (T (f-tail INT x y)) ) ; из контекстов flet и ; labels ) ; выход из контекста flet ) ; выход из контекста let* ) ; завершено определение INTERSECTION ) ; конец списка локальных рекурсивных функций

(defun UNION (x y) (let ( (a-x (CAR x)) (d-x (CDR x)) ) (COND ((NULL x) y) ((MEMBER a-x y) (UNION d-x y) ) (T (CONS a-x (UNION d-x y)) ) ) ) ) ; завершено определение на текущем уровне

(INTERSECTION '(A1 A2 A3) '(A1 A3 A5)) (UNION '(X Y Z) '(U V W X)) ) ; выход из контекста labels


Содержание раздела