Опубликован: 19.03.2004 | Уровень: специалист | Доступ: платный
Лекция 4:

Отображения и функционалы

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >

Функционалы - общее понятие

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

Для каждого числа из заданного списка получить следующее за ним число и все результаты собрать в список1Здесь и далее, следуя CLISP, (COND NIL) = NIL, т.е. допускается отсутствие предиката со значение "истина".

(DEFUN next (xl)                
;; Следующие числа*)    
   (COND                        ; пока список не пуст         
      (x (CONS (1+  (CAR xl))   ; прибавляем 1 к его "голове"                
            (next (CDR xl))  ; и переходим к остальным,
 )   )  )  )        ; собирая результаты в список
  (next '(1 2 5))         ; = (2 3 6)
4.1.

Построить список из <голов> элементов списка

(DEFUN 1st (xl)
                        ; "головы" элементов = CAR
  (COND                 ; пока список не пуст
    (xl (CONS (caar xl); выбираем CAR от его головы
      (1st (CDR xl))   ; и переходим к остальным,
) ) ) )                ; собирая результаты в список

(1st '((один два)(one two)(1 2)) )   ; = (один one 1)
4.2.

Выяснить длины элементов списка

(DEFUN lens (xl)    ; Длины элементов
   (COND            ; Пока список не пуст  
     (xl (CONS (length (CAR xl))  
                    ; вычисляем длину его головы
      (lens (CDR xl)); и переходим к остальным,
) ) ) )             ; собирая результаты в список  
   
  (lens '((1 2) () (a b c d) (1(a b c d)3)) )     
                   ; = (2 0 4 3)
4.3.

Внешние отличия в записи этих трех функций малосущественны, что позволяет ввести более общую функцию MAP-EL, в определении которой имена "CAR", "1+" и "LENGTH" могут быть заданы как значения параметра fn:

(DEFUN map-el(fn xl)
                 ; Поэлементное преобразование XL с помощью функции FN
   (COND         ; Пока XL не пуст
      (xl (CONS (FUNCALL fn (car xl)) 
             ; применяем FN как функцию к голове XL**)
         (map-el fn (CDR xl)) 
                  ; и переходим к остальным, 
) ) ) )            ; собирая результаты в список

Эффект функций NEXT, 1ST и LENS можно получить выражениями:

(map-el #'1+ xl)        ; Следующие числа:
(map-el #'CAR xl)       ; "головы" элементов = CAR
(map-el #'length xl)    ; Длины элементов

(map-el #'1+'(1 2 5))   ; = (2 3 6)
(map-el #'CAR'((один два)(one two)(1 2)) ) 
              ; = (один one 1)
(map-el #'length'((1 2)()(a b c d)(1(a b c d)3)) ) 
              ; = (2 0 4 3) соответственно.

Примечание. #’x – эквивалент ( FUNCTION x ), что является представлением функции в качестве аргумента.

Все три примера можно решить с помощью таких определяющих выражений:

(DEFUN next(xl)
	(map-el #'1+ xl)) ; Очередные числа:
(DEFUN 1st(xl)
	(map-el #'CAR xl)) ; "головы" элементов = CAR
(DEFUN lens(xl)
	(map-el #'length xl)) ; Длины элементов

Эти определения функций формально эквивалентны ранее приведенным - они сохраняют отношение между аргументами и результатами. Параметром функционала может быть любая вспомогательная функция.

Пусть дана вспомогательная функция sqw, возводящая числа в квадрат

(DEFUN sqw (x)(* x x)) ; Возведение числа в квадрат
(sqw 3)               ; = 9
4.4.

Построить список квадратов чисел, используя функцию sqw:

(DEFUN sqware (xl)
                  ; Возведение списка чисел в квадрат
   (COND      ; Пока аргумент не пуст,
      (xl (CONS (sqw (CAR xl))
                  ; применяем sqw к его голове
         (sqware(CDR xl))
                  ; и переходим к остальным,
) ) ) )          ; собирая результаты в список

(sqware'(1 2 5 7))      ; = (1 4 25 49 )

Можно использовать map-el:

(DEFUN sqware (xl) (map-el #'sqw xl))

Ниже приведено определение функции SQWARE- без вспомогательной функции, выполняющее умножение непосредственно. Оно влечет за собой двойное вычисление (CAR xl), т.е. такая техника не вполне эффективна:

(DEFUN sqware- (xl)
   (COND
      (xl (cons (* (CAR xl) (car xl) )
               ; квадрат "головы" списка
               ; "голову" вычислять приходится дважды
         (sqware- (CDR xl))
) ) ) )

Пусть дана вспомогательная функция TUPLE, превращающая любое данное в пару:

(DEFUN tuple (x) (CONS x x))  
(tuple 3)  ; = (3 . 3)
(tuple 'a)  ; = (a . a)
(tuple '(Ха))
   ; = ((Ха) . (Ха)) = ((Ха) Ха)
   ; - это одно и то же!
4.5.

Чтобы преобразовать элементы списка с помощью такой функции, пишем сразу:

(DEFUN duble (xl) (map-el #'tuple xl))
                        ; дублирование элементов 
(duble '(1(a)()))   ; = ((1 . 1)((a)a)(()))

Немногим сложнее организовать покомпонентную обработку двух списков.

Построить ассоциативный список, т.е. список пар из имен и соответствующих им значений, по заданным спискам имен и их значений:

(DEFUN pairl (al vl) ; Ассоциативный список
   (COND             ; Пока al не пуст,  
     (al (CONS (CONS (CAR al) (CAR vl))  
                     ; пары из <голов>.  
         (pairl (CDR al) (CDR vl))  
                     ; Если vl исчерпается,
                     ; то CDR будет давать NIL  
) ) ) )     

 (pair '(один два two three) '(1 2 два три))
 ; = ((один . 1)(два . 2)(two . два)(three . три))
4.6.

Определить функцию покомпонентной обработки двух списков с помощью заданной функции FN:

(DEFUN map-comp (fn al vl)  
        ; fn покомпонентно применить
        ; к соотвественным элементам al и vl  
  (COND     
    (al (CONS (FUNCALL fn (CAR al) (CAR vl))  
        ; Вызов данного fn как функции  
       (map-comp (CDR al) (CDR vl))
) ) ) )
4.7.

Теперь покомпонентные действия над векторами, представленными с помощью списков, полностью в наших руках. Вот списки и сумм, и произведений, и пар, и результатов проверки на совпадение:

(map-comp #'+'(1 2 3) '(4 6 9))
         ; = (5 8 12) Суммы
(map-comp #'*'(1 2 3) '(4 6 9))
         ; = (4 12 27) Произведения
(map-comp #'CONS'(1 2 3) '(4 6 9))
         ; = ((1 . 4) (2 . 6) (3 . 9)) Пары
(map-comp #'EQ'(4 2 3) '(4 6 9))
         ; = (T NIL NIL) Сравнения

Достаточно уяснить, что надо делать с элементами списка, остальное довершит функционал MAP-COMP, отображающий этот список в список результатов заданной функции.

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

(DEFUN mapf (fl el)  
   (COND  ; Пока первый аргумент не пуст,  
      (fl (CONS (FUNCALL (CAR fl) el)  
          ; применяем очередную функцию
          ; ко второму аргументу  
      (mapf (CDR fl) el)  
          ; и переходим к остальным функциям,
) ) ) )   ; собирая их результаты в общий
          ; список  

 (mapf '(length CAR CDR) '(a b c d))  
          ; = (4 a (b c d))
4.8.

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

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >
Дарья Федотова
Дарья Федотова
Сергей Березовский
Сергей Березовский

В рамках проф. переподготовки по программе "Программирование"

Есть курсы, которые я уже прошел. Но войдя в курс я вижу, что они не зачтены (Язык Ассемблера и архитектура ЭВМ, Программирование на С++ для профессионалов). Это как?

Алина Ленкова
Алина Ленкова
Россия, Ставрополь, СФ МГУПИ, 2014
Валерий Ромашов
Валерий Ромашов
Россия