Результат действия mapcar (2 6 24)
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

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

(defun decart (X Y)

(mapcar ('(lambda (X)

(mapcar ('(lambda (Y)

(list Y))) Y))) X)

)

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

$ (decart (A B C) (1 2 3))

(((A 1) (A 2) (A 3)) ((B 1) (B 2) (B 3)) ((C 1) (C 2)(C 3)))

Можно заметить, что обращение к функции mapcar следующим образом:

(mapcar FN (X1 X2 ... XN))

эквивалентно обращению к функции list:

(list (FN X1) (FN X2) ... (FN XN))

Функция (mapcar FN LIST1...LISTN) выполняет действия, предписанные функцией FN, над car-элементами списков LIST1,...,LISTN, затем - над cadr-элементами каждого списка, и т.д. до тех пор, пока каждый список не будет исчерпан. Функция mapcar возвращает список результатов. Например:

$ (mapcar '* '(2 3 5 7) '(2 4 6 8))

(4 12 30 56)

Рассмотрим функцию maplist.

Функция maplist действует подобно функции mapcar, но действия осуществляются не над элементами списка, а над последовательными cdr (начиная с исходного списка) этого списка. Приведем код функции для одного аргумента:

(defun maplist1 (F L)

(cond ( (null L) nil )

(T (cons (apply F L) (maplist F (cdr L))) )

)

)

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

$ (maplist '(lambda (Y) Y) '(A B C))

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

$ (maplist 'reverse '(A B C D))

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

(defun Deno ()

(print1 "Результат действия maplist: ")

(maplist Sum (1 2 3))

)

% Функция возвращает сумму элементов списка L %

(defun Sum (L)

(cond ( (nullL L) 0)

(T (+ (car L) (Sum (cdr L))) )

)

)

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

$ (Demo)

(6 5 3)

Функционалы mapcar и maplist используются для программирования циклов специального вида, поскольку с их помощью можно лаконично выразить повторяющиеся вычисления.

Рассмотрим функцию mapc.

(mapc F L) ,

где: F - имя функции или LAMBDA-выражение,

L - список.

Функция mapc последовательно применяет F к элементам списка, т.е. к (car L), (car (cdr L)) и т.д.

Код функции в muLISP81 таков:

(defun mapc1 (F L)

(cond ((null L) nil )

( (apply F (car L))

(mapcar1 F (cdr L)) )

)

)

Пример.

(defun primer (L) (+ (car L) 1) )

В системе muLISP функция (mapc FN LST11 ...LSTN) выполняет действия, указанные функцией FN над car-элементами списков LST1,...,LSTN, затем - над cadr -элементами каждого списка, и т.д. до тех пор, пока каждый список не будет исчерпан. Функция марс возвращает список LST1. Например:

$ (mapc 'prin1 '(1 2 3 4))

(1 2 3 4).

Eще один отображающий функционал: mapl. Функция (mapl FN LIST1 ... LISTN) выполняет действия, определенные функцией FN над последовательными cdr этих списков, начиная с исходных списков LIST1,...,LISTN, пока каждый список не будет исчерпан. Функция mapl возвращает LIST1. Например:

$ (mapl 'prin1 '(A B C))

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

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

mapcan, mapcon - объединяющие функционалы

Функция (mapcan FN LIST1 ... LISTN)выполняет действия, указанные в функции FN, над car-элементами списков LIST1,...,LISTN, затем - над cadr-элементами каждого списка, и т.д. до тех пор, пока каждый из списков не будет исчерпан. Функция mapcan связывает свои результаты-списки в единый список, игнорируя атомы.

Функционал mapcan удобен для выборки нежелательных элементов из списка. В приведенном примере показано, как можно удалить из списка отрицательные числа:

$(mapcan '(lambda (N) (or (< N 0)) (list N))) ‘(3 -7 4 0 -5 1))

(3 4 0 1)

Для сравнения:

$(mapcar '(lambda (N) (or (< N 0)) (list N))) ‘(3 -7 4 0 -5 1))

((3) T (4) (0) T (1))

Функция: (mapcon FN LIST1 ... LISTN)выполняет действия, указанные в функции FN, над последовательными cdr этих списков, начиная с исходных списков LIST1,...,LISTN, пока каждый список не будет исчерпан. Функция mapcon возвращает LIST1. Функция mapcon связывает свои результаты-списки в единый список, игнорируя атомы. Например:

$(mapcon 'reverse '(A B C D))

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

Функции mapcanиmapcon являются аналогами функций mapcorиmaplist. Отличие состоит в том, что mapcanиmapcon не строят, используя list, новый список из результатов, а объединяют списки, являющиеся результатами, в один список, игнорируя атомы (используется функцию Nconc).

2.9. Макросы

Часто бывает полезно не выписывать вычисляемое выражение вручную, а сформировать его с помощью программы. Для вычисления сформированного выражения программист всегда может вызвать интерпретатор eval.

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

При вызове макроса вначале из его аргументов строится некоторое выражение, задаваемое определением макроса. Затем это выражение вычисляется. Таким образом, макрос вычисляется как дважды.

Функция (defmacro M ARGL FORM1 ... FORMN)формирует S-выражение, компилирует его в D-код, модифицирует старое определение и возвращает M.

Примеры.

(defmacro My-Inc (S N)

((numberp N) (list 'setq S (list '+ S N)) )

(list 'setq S (list 'add1 S))

)

(defmacro My-Val L

((null L) )

( (null (cdr L)) (car L) )

)

(defmacro My-cond L

((null L) nil )

(cons 'cond (mapcar '(lambda (X) (list X)) L))

)

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

(defun push1 (A P)

(setq P (cons A (eval P)))

)

(defmacro push2 (A P)

(list 'setq P (list 'cons A P))

)

При вызове функции push1 в аргументах используются апострофы. При обращении к функции push 2апостроф не нужен.

Вызов макро (макровызов) представляет собой выражение (macro F1 F2 ... FN),где: macro - имя макрофункции, F1,F2,...,FN - фактические параметры макроса macro.

$ (setq S '(B C))

(B C)

$ (push1 'A 'S)

(A B C)

$ S

(B C)

$ (push2 D S)

(D B C)

$ S

(D B C)

Например, определим макрос, который позволяет в функции setq задавать второй аргумент без апострофа:

(defmacro My-setq (X Y)

(list 'setq X (list 'quote Y))

)

и вызовем его:

$ (My-setq S (A S D))

(A S D)

$ S

(A S D)

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

Если F есть макровызов, то функция (macroexpand-1 F)выполняет расширение макровызова F (осуществляет действия макрофункции над F) и возвращает сформированную программу, не исполняя ее. Например:

$ (macroexpand-1 '(my-inc x y ) )

(setq x (add1 x))

$ (macroexpand-1 '(my-inc x 1 ) )

(setq x (+ x 1))

$ (macroexpand-1 '(my-cond x 1 ) )

(cond (x) (1))

$ (macroexpand-1 '(my-cond x 1 ) )

Nil

$ (macroexpand-1 '(push2 d s ) )

(setq s (cons d s))

$ (macroexpand-1 '(my-setq s (a s d)) )

(setq s (quote (a s d))))

Приведем еще один пример. Определим рекурсивный макрос:

(defmacro my-copy-list (x)

(cond ( (null x) nil )

(T (list 'cons (list 'quote (car x))

(list ' my-copy-list (cdr x))

) ) ) )

и обратимся к функции macroexpand-1:

$ (my-copy-list (a s d))

(a s d)

$ (macroexpand-1 '(my-copy-list (a s d)))

(cons (quote a) (my-copy-list (s d)))

Если F есть макровызов, то функция (Macroexpand-1 F)повторно расширяет F до тех пор, пока результат расширения не будет макровызовом.

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