Функция 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, просмотров: 224.