На этом шаге мы рассмотрим функцию MAPCAR.
Рассмотрим вначале две функции.
(DEFUN SUMADD (LAMBDA (LST) % Функция, преобразующая список целых чисел в список, % % каждый из элементов которого на единицу больше % % соответствующего элемента % ( (NULL LST) NIL ) ( CONS (PLUS 1 (CAR LST)) (SUMADD (CDR LST)) ) )) % ------------------------ % (DEFUN TANUSHA (LAMBDA (LST) % Функция, преобразующая список целых чисел в список, % % каждый из элементов которого представляет собой ос- % % таток от деления соответствующего элемента на 2 % ( (NULL LST) NIL ) ( CONS (REMAINDER (CAR LST) 2) (TANUSHA (CDR LST)) ) ))
Очевидно, что есть нечто общее в структуре данных функций.
Возникает естественный вопрос: возможно ли обобщение?
Ниже мы построим функцию MAPCAR для диалекта muLISP81, с помощью
которой вторая интересующая нас проблема решается так:
$ (MAPCAR REMAINDER (2 4 6))
(0 0 0)
Обращение к функции MAPCAR выглядит следующим образом:
(MAPCAR FN (X1 X2 ... XN))
Значение функции MAPCAR вычисляется путем применения функции FN к последовательным элементам Xi списка, являющегося вторым аргументом MAPCAR.
В качестве значения функционала возвращается список, построенный из результатов вызовов функционального аргумента MAPCAR.
Код функции для muLISP81 достаточно прост:
(DEFUN MAPCAR (LAMBDA (FUN LST) (COND ( (NULL LST) NIL ) ( CONS (FUN (CAR LST)) (MAPCAR FUN (CDR LST)) ) ) ))
Отметим здесь, что вычисление функционала MAPCAR может быть осуществлено параллельно и не зависит от порядка обработки элементов списка.
$ (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 МИМО 3)) (T T NIL T)
(DEFUN DEMO (LAMBDA (FUN LST) (PRIN1 "Результат действия MAPCAR: ") (MAPCAR FUN LST) )) % ------------------- % (DEFUN FACT (LAMBDA (X) (COND ( (ZEROP X) 1 ) ( T (TIMES X (FACT (DIFFERENCE X 1))) ) ) )) % --------------------------- % (DEFUN MAPCAR (LAMBDA (FUN LST) (COND ( (NULL LST) NIL ) ( T (CONS (FUN (CAR LST)) (MAPCAR FUN (CDR LST))) ) ) ))
$ (DEMO FACT (2 3 4)) (2 6 24)
(DEFUN DECART (LAMBDA (X Y) % X и Y - списки % (MAPCAR (QUOTE (LAMBDA (X) (MAPCAR (QUOTE (LAMBDA (Y) (LIST X Y))) Y))) X) )) % --------------------------- % (DEFUN MAPCAR (LAMBDA (FUN LST) (COND ( (NULL LST) NIL ) ( T (CONS (FUN (CAR LST)) (MAPCAR FUN (CDR LST))) ) ) ))
$ (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 FN (X1 X2 ... XN))эквивалентно обращению к функции LIST:
(LIST (FN X1) (FN X2) ... (FN XN))
Замечание 2. Функция (MAPCAR FN LIST1...LISTN) выполняет действия,
предписанные функцией FN, над CAR-элементами списков
LIST1,...,LISTN, затем - над CADR-элементами каждого списка, и т.д.
до тех пор, пока каждый список не будет исчерпан. Функция MAPCAR возвращает список
результатов. Например:
$ (MAPCAR '*'(2 3 5 7) '(2 4 6 8))
(4 12 30 56)
Код функции в системе muLISP85 имеет вид:
(DEFUN MAPCAR (FUNC LST1 LST2) ( (OR (NULL LST1) (NULL LST2)) NIL ) (CONS (FUNCALL FUNC (CAR LST1) (CAR LST2)) (MAPCAR FUNC (CDR LST1) (CDR LST2))) )
На следующем шаге мы продолжим изучение отображающих функционалов, в частности, рассмотрим функцию MAPLIST.