Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Вариант_№28.doc
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
802 Кб
Скачать
☆

Функционалы

В математике под функционалом понимается функция, имеющая своим аргументом другую функцию. Соответственно, в языках программирования, в том числе в Lisp, функционалом является функция, принимающая некоторыми своими аргументами "процедурный" тип данных.

Первым делом параметр-функцию надо передать, подавив её вычисление. Для этого используется функция FUNCTION

function

(function функция аргументы)

Функция позволяет подавить вычисление своего параметра. Действует аналогично QUOTE, но для аргументов функционального типа. В большинстве случаев функциональный параметр используется вместе с QUOTE, однако FUNCTION может быть использована для указания, что в качестве параметра следует ждать именно функцию.

Другая задача - вычислить переданный таким образом аргумент.

funcall

(funcall функция)

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

>(FUNCALL

(FUNCTION

(LAMBDA (X Y) (* X Y))

)

2 4)

8

В приведённом примере с помощью LAMBDA задаётся функция, принимающая два аргумента и возвращающая их произведение. Вычисление этой функции подавляется с помощью FUNCTION (иначе мы получили бы ошибку о недопустимом числе аргументов). Затем над результатом, а именно функциональным аргументом, выполняется FUNCALL, с указанием двух аргументов - 2 и 4. Как видно, результатом было искомое произведение.

Приведём пример использования функционала. Например, мы хотим вычислить экстремум в некоторой последовательности:

>(defun extremum (lst fn el)

(cond

((eq (cdr lst) nil) (car lst))

((funcall fn (car lst) (extremum (cdr lst) fn el)) (car lst))

(T (extremum (cdr lst) fn el))))

EXTREMUM

Теперь вычислим минимум и максимум в последовательностях:

>(extremum '(6 -3 1 2 3) (function <) 1000)

-3

>(extremum '(6 -3 1 2 3) (function >) -1000)

6

Таким образом, в зависимости от переданного в функцию функционального аргумента (< или >) мы вычисляем минимум или максимум. Третьим параметром функции является условно наибольшее и наименьшее число. В принципе, можно таковым считать первый символ последовательности (пример апеллирует к определённой ранее функции EXTREMUM).

>(defun extremum2 (lst arg)

(extremum (cdr lst) arg (car lst)))

EXTREMUM2

>(extremum2 '(1 2 3) (function <))

1

>( extremum2 '(1 2 3) (function >))

3

В Lisp присутствует также некоторое количество стандартных функций с функциональными аргументами, которые в основном также как и в нашем примере реализуют работу с последовательностями. Различают два основных класса функционалов - отображающие и применяющие. Применяющими функционалами являются уже известный нам FUNCALL, а также APPLY.

apply

(apply функция аргумент)

Функционал применяет некоторую функцию к аргументам, которые заданы списком в качестве второго параметра APPLY

>(apply 'car '((a b)))

A

>(funcall 'car '((a b)))

(A B)

Отметим, что не все функции могут использоваться в качестве функциональных аргументов, например, использование OR и AND даёт ошибку (интерпретатор аргументирует это тем, что OR, AND и некоторые другие функции имеют некую специальную реализацию).

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

mapcar

(mapcar функция список)

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

>(mapcar 'null '(() (a b) (nil c d)))

(T NIL NIL)

>(mapcar '(lambda (x) (cons x nil)) '(a b c))

((A) (B) (C))

maplist

(maplist функция список)

Функция, позволяющая выполнить некоторое вычисление последовательно над хвостовыми частями списка. Сперва вычисляется функция от списка, затем (CDR список), затем (CDDR список), (СDDDR список) и так далее. Результатом является список, построенный из результатов применения функционального аргумента к хвостовым элементам списка.

>(maplist '(lambda (x) x) '(a b c))

((A B C) (B C) (C))

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

>(defun max2 (lst)

(progn

(setq x (car lst))

(mapcar '(lambda (y) (if (< x y) (setq x y))) lst)

x))

MAX2

>(max2 '(1 2 3))

3

mapcan

mapcon

(mapcan функция список)

(mapcon функция список)

Аналоги MAPCAR и MAPLIST, однако при своей работе строят список, используя функцию NCONC, т.е. потенциально структура исходных данных может разрушиться. Эти функционалы называются объединяющими, и одно из основных проявлений их особенностей заключается в уничтожении всех вхождений NIL в результирующий список.

>(setq x '(A B C))

(A B C)

>(mapcar 'list x)

((A) (B) (C))

>(mapcan 'list x)

(A B C)

>(maplist 'list x)

(((A B C)) ((B C)) ((C)))

>(mapcon 'list x)

((A B C) (B C) (C))

Используем способность объединяющих функционалов уничтожать NIL для написания функции, проверяющей вхождение элемента в список:

>(defun isinlist (lst el)

(car

(mapcan

(function

(lambda (y)

(if (eql y el) '(t) nil)))

lst)))

ISINLIST

>(isinlist '(1 2 3) 2)

T

>(isinlist '(1 2 3) 4)

NIL

mapc

mapl

(mapc функция список)

(mapl функция список)

Аналоги MAPCAR и MAPLIST, однако эти функции не строят никакого нового результата, а просто возвращают исходный список. Таким образом, для них может быть важен только некоторых побочный результат, в том случае, если использованная в качестве параметра функция содержит в той или иной форме присвоение, вывод на экран и т.п.

В качестве примера такого побочного действия рассмотрим вывод на экран.

>(mapc 'print '(A B C))

A

B

C

(A B C)

Таким образом, все элементы списка были по очереди выведены, а в качестве результата вернулся исходный список. Очевидно, этот же эффект мог быть достигнут и MAPCAR, и MAPCAN, однако при этом не тратились ресурсы на конструирование новых структур в памяти.

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

>(mapcar '* '(1 2 3) '(4 5 6))

(4 10 18)

Или, например, попарное объединение элементов двух списков:

>(mapcar 'list '(1 2 3) '(4 5 6))

((1 4) (2 5) (3 6))

Расширением этого примера может быть вычисление скалярного произведения двух векторов (в примере [1 2 3] и [4 5 6]):

>(apply '+ (mapcar '* '( 1 2 3) '(4 5 6)))

32

В случае, если у списков параметров не совпадают размеры, лишние элементы списков будут просто проигнорированы:

>(mapcar 'list '(1 2 3) '(4 5))

((1 4) (2 5))

Для MAPC и MAPL возвращаемым значением всегда будет первых аргумент-список.

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