Функции высших порядков. Функционалы.
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Функция eval - интерпретатор языка LISP.

До сих пор мы рассматривали функции, которые в качестве аргументов получали выражения, не являющиеся функциями.

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

Функция eval - это функция, которая может вычислить любое правильно составленное выражение языка LISP. Например:

$ (eval (+ 2 3))

$ (eval (list (read) (read) (read)))

+

«Лишний» вызов интерпретатора может, например, снять эффект блокировки вычисления при помощи функции quote или позволяет найти значение значения выражения. Например:

$ (eval (quote (+ 1 2)))

quote и eval действуют «во взаимно противоположных направлениях» и аннулируют эффект друг друга.

Для функции eval нет аналогий в языках императивного программирования. Используя eval, мы можем выполнить «оператор», который в действительности создан нашей LISP-программой и который может меняться в процессе выполнения программы.

Диалог с интерпретатором языка LISP на самом верхнем, командном уровне, можно описать простым циклом:

(print (quote _)) %Вывод приглашения%

(print (eval (read)))% Ввод выражения и%

%вычисление его значения%

(print (quote _)) %Повторение вывода приглашения%

... ...

Интерпретатор отвечает на заданный ему вопрос и ждет новое задание.

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

apply, funcall - аппликативные функционалы.

Если F - имя встроенной или определенной пользователем функции или тело lambda, A =(A1 A2...AN) – список, то функция apply связывает формальные аргументы функции F с фактическими аргументами (A1 A2...AN), вычисляет тело функции, восстанавливает первоначальное значение формальных аргументов и возвращает значение вычисления тела функции. Например:

$ (apply 'cons '(A (B C D)))

(A B C D)

$ (apply '(lambda (N) (* N N)) '(5))

Если функция F не является именем функции или телом функции Lambda, то apply генерирует прерывание по ошибке «Неопределенная функция».

(defun apply1 (F A)

(eval (cons F A))

)

(defun eval1 (F)

(apply (car F) (cdr F))

)

Если функция (funcall F A1 A2...AN) осуществляет выполнение действий F над аргументами A1,A2,...,AN и возвращает результат. Параметр F (функция) должен быть именем функции, или lambda-формой. Например:

$ (funcall 'cons 'A '(B C D))

(A B C D)

$ (funcall '(lambda (N) (* N N)) 5)

Если функция F - это имя макро или неопределенной функции, то возникает прерывание по ошибке «Неопределенная функция».

Функционал funcall по своему действию аналогичен функционалу apply, но аргументы для вызываемой функции он принимает не списком, а «по отдельности». Синтаксис функционала:

(funcall FN X1 X2...XN)

Например:

$ (funcall '+ 2 3)

mapcar, maplist, mapc, maplist - отображающие функционалы

Важный класс функционалов образуют отображающие функционалы (map -функции). map -функции - функции, которые отображают исходный список в новый список или порождают побочный эффект, связанный с исходным списком.

Имена map -функций начинаются с префикса map, и их вызов имеет вид:

(map* FN L1 L2 ... LN)

Здесь:

* - определенная последовательность символов (продолжение названия функции);

L1,...,LN - списки;

FN - функция N аргументов.

Если map -функция применяется к одному аргументу-списку, то FN является функцией одного аргумента:

(map* FN LIST)

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

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

Во всех случаях число аргументов-списков должно совпадать с числом аргументов используемой для вычислений функции.

Рассмотрим функцию mapcar. Для этого рассмотрим вначале две функции.

% Функция, прибавляющая единицу к каждому элементу списка целых чисел %

(defun Summ (L)

(cond ((Null L) Nil ))

(T (cons (+ (car L)) (Summ (cdr L))))

)

)

% Функция, вычисляющая остаток от деления на 2 элементов списка целых чисел %

(defun Rems (L)

(cond ((null L) Nil )

(T (cons (remainder(car L) 2) (Rems (cdr L))))

)

)

Очевидно, что есть нечто общее в структуре данных функций. C помощью функции mapcar вторая функция определяется так:

$ (mapcar 'remainder '(2 4 6))

(0 0 0)

Значение функции mapcar вычисляется путем применения функции FN к последовательным элементам Xi списка, являющегося вторым аргументом mapcar.

В качестве значения функционала возвращается список, построенный из результатов вызовов функционального аргумента mapcar.

Код функции mapcar для одного аргумента достаточно прост:

(defun mapcar1 (F L)

(cond ((null L) nil )

(cons (apply F (car L))

(T (mapcar1 F (cdr L)) )

)

)

Примеры применения.

$ (mapcar 'atom '(A B C))

(T T T)

$ (mapcar '(lambda (Y) (list (print Y))) '(A B C))

A

B

C

((A) (B) (C))

$ (putd Para1 (lambda (X) (list X 1)))

Para1

$ (mapcar Para1 X)

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

$ (mapcar numberp (1 2 nonumb 3))

(T T nil T)

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

(defun Demo (lambda (F L)

(prin1 «Результат действия mapcar: «)

(mapcar F L)

))

(defun Fact (X)

(cond ((equal X 0) 1 ) (T (* X (Fact (- X 1))) )

))

Протестируем определения функций.

$ (Demo Fact (2 3 4))

Дата: 2016-10-02, просмотров: 190.