Новосибирский Государственный Университет
Опубликован: 05.02.2007 | Доступ: свободный | Студентов: 2222 / 413 | Оценка: 4.30 / 4.23 | Длительность: 10:15:00
Лекция 7:

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

< Лекция 6 || Лекция 7: 123 || Лекция 8 >
(defun tuple (x) (cons x x))
(tuple 3)             ; = (3 . 3)
(tuple 'a)       ; = (a . a)
(tuple '(Ха))    
     ; = ((Ха).(Ха))=((Ха)Ха)-это одно и то же!
7.5. Пусть дана вспомогательная функция tuple, превращающая любое данное в пару:

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

(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
)    )  )   )

(pairl '(один два two three) '(1 2 два три))
         ; = ((один . 1)(два . 2)(two два )(three три ))
7.6. Построить ассоциативный список, т.е. список пар из имен и соответствующих им значений, по заданным спискам имен и их значений:
(defun map-comp (fn al vl) ; fn покомпонентно применить
         ; к соответственным элементам AL и VL
     (cond
        (xl (cons (funcall fn (car al) (car vl))         
           ; Вызов данного FN как функции
                  (map-comp (cdr al) (cdr vl))
)    )  )   )
7.7. Определить функцию покомпонентной обработки двух списков с помощью заданной функции fn:

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

(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))
7.8. Для заданного списка вычислим ряд его атрибутов, а именно - длина, первый элемент, остальные элементы списка без первого.

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

Безымянные функции

Определения в примерах 4 и 5 не вполне удобны по следующим причинам:

  • В определениях целевых функций duble и sqwure встречаются имена специально определенных вспомогательных функций.
  • Формально эти функции независимы, значит программист должен отвечать за их наличие при использовании целевых функций на протяжении всего жизненного цикла программы, что трудно гарантировать.
  • Вероятно, имя вспомогательной функции будет использоваться ровно один раз - в определении целевой функции.

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

Учитывая это, было бы удобнее вспомогательные определения вкладывать непосредственно в определения целевых функций и обходиться при этом вообще без имен. Конструктор функций lambda обеспечивает такой стиль построения определений. Этот конструктор любое выражение expr превращает в функцию с заданным списком аргументов (x1 ... xK) в форме так называемых lambda-выражений:

( lambda (x1 ... xK) expr )

Имени такая функций не имеет, поэтому может быть применена лишь непосредственно. Defun использует этот конструктор, но, кроме того, дает функциям имена.

(defun sqware (xl)(map-el(lambda(x)(* x x))xl))
(defun duble (xl)(map-el(lambda(x)(cons x x))xl))
7.9. Определение функций duble и sqwure из примеров 4 и 5 без использования имен и вспомогательных функций:

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

< Лекция 6 || Лекция 7: 123 || Лекция 8 >