Search
Write a publication
Pull to refresh

Comments 6

Немного коробит, когда Scheme обзывают "схемой". Ну и считают этот язык Lisp-ом.

А что касается объектной модели программирования на Scheme, то об этом можно почитать в небезызвестной и непреходящей SICP.

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

Да, в SICP, насколько помню, macro-средства не рассматриваются. А это одна из самых интересных частей Scheme.

Вам дальнейших успехов в постижении Scheme. Как говорится, пишите ещё! :)

Статья несколько непоследовательная в том отношении, что сначала критикуется форма cond с перебором значений fig-type (кстати, напрашивающаяся на замену на case, если такая форма есть в этом диалекте), а потом в ООП-подходе происходит переход к каким-то счётчикам, и остаётся совершенно непонятным, действительно ли ООП позволит улучшить этот несчастный cond. Я, например, не понял, как именно вы предлагаете наследовать pencil, brush и shape от figure, а если наследования не будет – то куда денется тот самый вызвавший критику cond. Сам по себе диспетчер никак не решает эту проблему. Мне кажется, было бы правильно отразить в статье обе реализации целиком.

А я бы лично для решения на Scheme заявленной задачи, скорее всего, построил бы ассоциативный список, в котором ключом был бы тип, а значением – лямбда с кодом для рисования, и написал бы что-то вроде

(cond
  ((assq (fig-type fig) alist) => 
      (lambda (x) ((cdr x) fig)))
  (else (raise "type error")))

Спасибо за замечание! Вы правы, в данной статье НЕТ НАСЛЕДОВАНИЯ. т.е я его не реализовывал, и обозначенная в самом начале статьи проблема решается через сигнал, допустим :draw, которые различные классы объектов, должны реализовать самостоятельно, таким образом каждый объект, будет исполнять свой код, а основная программа просто для любого объекта посылать им сигнал :draw. Тут как бы дело не в наследовании, которое в обычном ООП обеспечивает нам перегрузку методов, и в свою очередь при этом обеспечивается, полиморфное поведение. Здесь просто интерфейс "виртуальных" сигналов, обработку которых должен обеспечить каждый класс.

Другое дело, что наследование помогло бы нам избежать дублирования кода, который мы могли бы определить как поведение для базового класса, а различающийся код, определять в наследниках. Но на то это и простая реализация, что бы не влезать в дебри реализации наследования. Я вот пока не знаю как описать то что я написал в obj4.scm, где и реализовано наследование, причём множественное, да что там говорить практически аналог CLOS по возможностям, но без MOP. С помощью этой системы я прорешал примеры из книги "Теория вычисления для программистов" Тома Стюарта. А код там выполнен на Ruby. И по выразительности моего кода, я бы не сказал что он сильно уступает коду на Ruby. Но вот пример:

;;стр 75 предложения

(defclass Statement (Object) ())
;;простейшее из предложений ничего не делает
(defclass DoNothing (Statement) ())

(defmethods DoNothing
  (inspect (cycle)
    "do-nothing")
  (evaluate (env)
     env)
  (to-scheme ()
     (eval `(lambda (env) env)))
  )

(defclass Assign (Statement)
  (name expression))

(defmethods Assign
  (inspect (cycle)
    (with-slots ((name expression) self)
       (join-to-str name " = " (inspect expression cycle) )))
  (evaluate (env)
    (with-slots ((name (expr expression)) self)
      (env-set env name (evaluate expr env))
	 ))
  (to-scheme ()
     (eval `(lambda (env) (env-set env
                                   ',(vfield self :name)
                                   (,(to-scheme (vfield self :expression)) env)))))
  )

(short-make Assign! Assign :name :expression)
(short-make DoNothing! DoNothing)

(define st1 (Assign! 'y (Add! (Variable! 'x) (Number! 1))))
(inspect st1 #f) ;; "y = (x+1)"
(get-closure-code (to-scheme st1))
;(lambda (env) (env-set env 'y (#<CLOSURE> env)))
(prn (to-scheme st1))
;; #CLOSURE(lambda (env)
;;            (env-set env (quote y)
;;                     (#CLOSURE(lambda (env)
;;                                 (+ (#CLOSURE(lambda (env) (env-get env (quote x))) env)
;;                                    (#CLOSURE(lambda (env) 1) env))) env)))

но в отличии от автора, я выполнял денотацию не в Ruby, а в Scheme. И этот код выполнялся в GIMP script-fu.

Интересный синтаксис определения классов. Я если буду улучшать свой littlelisp.js возможно попробую перенять некоторые конструкции.

Правда, пересылка сообщений, на мой взгляд, усложнение. Можно и просто сделать поиск и вызов метода объекта.

Sign up to leave a comment.

Articles