- •ОгЛавление
- •8 Литература 93
- •Лабораторная работа №1 Знакомство с языком логического программирования Пролог
- •1.1 Цель работы
- •1.2 Теоретические сведения
- •1.3 Среда VisualProlog
- •1.4 Выполнение работы
- •1.5 Задание на лабораторную работу
- •2.3 Выполнение работы
- •2.4 Задание на лабораторную работу
- •2.5 Контрольные вопросы
- •Лабораторная работа №3 Рекурсивные структуры данных
- •3.1 Цель работы
- •3.2 Теоретические сведения
- •3.3 Выполнение работы
- •3.4 Задание на лабораторную работу
- •3.5 Контрольные вопросы
- •Лабораторная работа №4 Знакомство с языком списочных структур Лисп
- •4.1 Цель работы
- •4.2 Теоретические сведения
- •4.3 Среда FreeLisp
- •4.4 Выполнение работы
- •4.5 Задание на лабораторную работу
- •4.6 Контрольные вопросы
- •Лабораторная работа №5 Рекурсия и итерация в языке Лисп
- •5.1 Цель работы
- •5.2 Теоретические сведения
- •5.3 Выполнение работы
- •5.4 Задание на лабораторную работу
- •5. 5. Контрольные вопросы
- •6.2.2 Замыкания
- •6.2.3 Макросы
- •6.3 Задание на лабораторную работу
- •6.4 Контрольные вопросы
- •Лабораторная работа №7 Методы поиска решений в пространствах состояний
- •7.1 Цель работы
- •7.2 Теоретические сведения
- •7.4 Выполнение работы
- •7.5 Задание на лабораторную работу
- •7.6 Контрольные вопросы
- •8 Литература
6.2.2 Замыкания
Функциональный аргумент можно пометить с помощью специальной, предотвращающей вычисления формы FUNCTION:
(FUNCTION функция)
В отличие от обычной блокировки вычислений с помощью QUOTE форму FUNCTION называют функциональной блокировкой. Функциональную блокировку можно записывать сокращенно:
#’f (FUNCTION f)
Если нужно передать функции данные в том виде, как они записаны, то используется обычная форма quote. Функции quote достаточно и для передачи имени функции или лямбда-выражения, если в нем не используются свободные переменные. Работа со свободными переменными оказывается более сложной, чем с параметрами, поскольку значения свободных переменных зависят от контекста вычислений. Сформированный на время вычисления функции вычислительный контекст после окончания ее вычисления пропадает, и на него невозможно позже сослаться или вернуться к нему. Для запоминания контекста вычисления в Лиспе используется замыкание (лексическое замыкание) – пара, состоящая из функции (лямбда-выражения) и контекста.
Замыкание создается формой FUNCTION. В замыкание из контекста определения функции включаются лишь связи свободных переменных функции. Замыкание можно сохранять как любой лисповский объект, присваивая его какой-нибудь переменной:
>(defun add(x)
(function (lambda (y) (+ x y))))
ADD
>(setq add3 (add 3)) ; x = 3
#<Closure SPECIAL::APPLY-INTERPRETED-CLOSURE ...>
>(funcall add3 5) ; y = 5
8
Связи свободных переменных замыкания остаются в силе до следующего запуска замыкания, и этим переменным можно даже присваивать новые значения.
Необходимость замыканий продемонстрируем на следующем примере. Допустим, Вы хотите написать программу, которая при вызове генерирует степени двойки. Это должно выглядеть следующим образом:
>(power-of-2-generator)
2
>(power-of-2-generator)
4
>(power-of-2-generator)
8
...
Один из способов написать такой генератор – использовать глобальные переменные:
(defvar *previous-power* 1)
(defun power-of-2-generator ()
(setf *previous-power* (* 2 *previous-power*)))
Функция работает, но она использует глобальные переменные, а это значит, что мы не можем иметь больше одного power-of-2-generator генератора одновременно, так как глобальная переменная *previous power* может сохранять только одно значение.
Можно ли обойтись без глобальных переменных? Для сохранения состояния генератора может быть использовано замыкание. Связи свободных переменных замыкания остаются в силе до следующего запуска замыкания. Этим переменным также можно присваивать значения. Используя замыкание, получим следующее определение генератора степеней двойки:
(defun make-power-of-2-generator (previous-power)
#'(lambda ()
(setf previous-power (* previous-power 2))))
Теперь мы можем создать несколько генераторов, так как каждый из них использует собственную переменную previous-power.
>(setf g1 (make-power-of-2-generator 1))
#<Closure SPECIAL::APPLY-INTERPRETED-CLOSURE ...>
>(setf g2 (make-power-of-2-generator 10))
#<Closure SPECIAL::APPLY-INTERPRETED-CLOSURE ...>
>(funcall g1)
2
>(funcall g2)
20
>(funcall g1)
4
>(funcall g2)
40
>(funcall g1)
8
