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

От ФП к ООП

< Лекция 9 || Лекция 10: 12345 || Лекция 11 >

Средства ООП в CLOS на базе стандарта Clisp

Показанный в [7] пример работает по первому аргументу (выбор подходящего метода рассчитан на то, что достаточно разобраться с одним аргументом), CLOS делает это на всех аргументах, причем с рядом вспомогательных средств, обеспечивающих гибкий перебор методов и анализ классов объектов.

Классы и экземпляры объектов

(defclass ob () (f1 f2 ...))

Это означает, что каждое вхождение объекта будет иметь поля-слоты f1 f2 ... ( Слот — это поле записи или списка свойств.) Чтобы сделать представителя класса, мы вызываем общую функцию:

(SETF с (make-instance 'ob))

Чтобы задать значение поля, используем специальную функцию:

(SETF (slot-value c) 1223)

До этого значения полей были не определены.

Свойства слотов

Простейшее определение слота — это его имя. Но в общем случае слот может содержать список свойств. Внешне свойства слота специфицируются как ключевые параметры функции. Это позволяет задавать начальные значения. Можно объявить слот совместно используемым.

:allocation :class

Изменение такого слота будет доступно всем экземплярам объектов класса. Можно задать тип элементов, заполняющих слот, и сопроводить их строками, выполняющими роль документации.

Суперкласс

Нет необходимости все новые слоты создавать в каждом классе.

Пример: ОО-определение Лисп-компилятора.

;oop-compile
 
    (defclass expr () 
    ((type :accessor td) 
     (sd :accessor ft))
    (:documentation "C-expression"))
 
    (defclass un (expr)
                   ; \_____суперкласс для унарных форм
 
       ((type :accessor td) ;; можно унаследовать,
         (sd :accessor ft)) ;; а здесь не дублировать
    (:documentation "quote car *other *adr"))
 
    (defclass bin (expr) 
       ((type :accessor td) 
         (sd :accessor ft)
         (sdd :accessor sd) )
    (:documentation "cons + lambda let"))
 
    (defclass trio (expr) 
               ;; (bin)  тогда можно не объявлять первые 3 поля
       ((type :accessor td) 
        (sd :accessor ft)
        (sdd :accessor sd)
        (sddd :accessor td) )
    (:documentation "if label"))
 
    (defmethod texrp ((x expr) (nt atom))
       (SETF (slot-value x 'type) nt)
       (SETF (td x) nt) ;;--;; variant
    (:documentation "объявляем тип выражения"))
 
    (defmethod spread ((hd (eql 'QUOTE))
                                  (tl expr))
       (let (  (x (make-instance 'un)) )
          (SETF (ft x) (car tl))
          (SETF (td x) hd)
    ) (:documentation "распаковка выражения"))
 
    (defmethod compl ((hd (eql 'QUOTE))
                                 (tl expr))
          (list 'LDC tl)
     (:documentation "сборка кода"))
 
    (defmethod compl ((hd (eql 'CAR))
                                 (tl expr))  N)
          (append (compl(ft tl) N) '(CAR))
     (:documentation "сборка кода"))
 
    (defmethod spread ((hd (eql 'CONS))
                                  (tl expr))
       (let ( (x (make-instance 'bin)) )
          (SETF (ft x) ( CAR tl))
            (SETF (sd x) ( cadr tl))
            (SETF (td x) hd)
    ) (:documentation "распаковка выражения"))
 
    (defmethod compl ((hd (eql 'CONS))
                                (tl bin) N )
             (append (compl(sd tl) N) (compl(ft tl) N) 
             '(CONS))
     (:documentation "сборка кода"))
    (defmethod compl ((hd (eql '+))
             (tl bin) N )
             (append (compl(ft tl) N) (compl(sd tl) N) 
             '(ADD))
     (:documentation "сборка кода"))
 
    (defmethod spread ((hd (eql 'IF))
             (tl expr))
       (let ( (x (make-instance 'trio)) )
          (SETF (ft x) ( CAR tl))
          (SETF (sd x) ( cadr tl))
          (SETF (td x) ( caddr tl))
          (SETF (td x) hd)
    ) (:documentation "распаковка выражения"))
 
    (defmethod compl ((hd (eql 'IF))
                                (tl expr) N )
       (let ( (then (list (compl(sd tl) N) '(JOIN)))
          (else (list (compl(td tl) N) '(JOIN))) )
          (append (compl(ft tl) N) (list 'SEL then else)
          )
    )(:documentation "сборка кода"))
 
    (defmethod parh ((x expt))
       (let (ftx (ft x))
          (COND
             ((ATOM ftx) (spread 'ADR ftx))
             ((member (CAR ftx) 
              '(QUOTE CAR CONS + IF LAMBDA LABEL LET))
             (spread (CAR ftx) (CDR ftx))
             (T (spread 'OTHER ftx) ))
    )(:documentation "шаг разбора"))
 
    ;====test==========
    (SETF test1 (make-instance 'expr))
    (texpr test1 'expr)
    (SETF (slot-value test1 'sd) (READ))
    ()
 
    (SETF e1 (make-instance 'expr))
    (SETF e2 (make-instance 'expr))

    (SETF e3 (make-instance 'expr))  
       (print (tf e2))
    (SETF (slot-value e3 'type) 'expr)
       (print (tf e3))

    (SETF (slot-value e3 'sd) '(QUOTE const))
 
    (defmethod ep ((x expr))
       ((LAMBDA (xt)
          (SETF (slot-value x 'type) xt) )
        (CAR (slot-value x 'sd)) ) )
    (print (ep e3))
    (print (tf e3))
    (print (td e3))
    (print (sd e3))
 
    (defmethod ep-q ((x (eql 'QUOTE)) (y expr))
    (SETF y (make-instance 'un)))

    (SETF (slot-value y 'type) 'QUOTE)
    (SETF (slot-value y 'sd) y)

    (print (tf (e3 'sd)))
 
    (print (tf e1))
    (print(SETF (slot-value e1 'type) (tf e1)))
    (SETF (slot-value e2 'sd) 'atom1)
    (print (tf (sd e2)))
 
    (print(SETF (slot-value e3 'sd) '(QUOTE const)))
    (print (tf e3))

CLOS, естественно, использует модель обобщенных функций, но мы написали независимую модель, используя более старые представления, тем самым показав, что концептуально ООП — это не более чем перефразировка идей Лиспа. ООП — это одна из вещей, которую Лисп изначально умеет делать. Для функционального стиля программирования в переходе к ООП нет ничего революционного. Такой переход практически не расширяет пространство предстоящих решений. Это просто небольшая конкретизация механизмов перебора ветвей функциональных объектов Императивному стилю ООП компенсирует избыточную целостность представления отлаживаемых программ, смягчает жесткость зависимости компонентов программы от потока информационных процессов.

Более интересный вопрос, что же нам еще может дать функциональный стиль и лисповская традиция реализации систем программирования?

Ответу на этот вопрос посвящены три следующие лекции.

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

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

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

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