Некоторые дополнительные подсказки о вашем коде.
Классы
Не жесткое правило, но функции доступа (которые являются общими функциями) часто называют только по слоту, то есть x
, а не get-X
(определенно "плохой" стиль) или object-X
( не плохо , все еще довольно часто).
(defclass line ()
((start :initarg :start :accessor start)
(end :initarg :end :accessor end)))
(defclass cart ()
((x :initarg :x :reader x)
(y :initarg :y :reader y)))
(defclass rect ()
((upper-left :initarg :upper-left :accessor upper-left)
(bootom-right :initarg :bottom-right :accessor bottom-right)))
Я не знаю, каковы ваши требования, поэтому я изобрел некоторые; в частности, я представляю прямоугольники как 2 точки (верхний левый и нижний правый).
Функции конструктора
Наличие функций конструктора очень помогает иметь краткий и читаемый код:
(defun cart (x y)
(make-instance 'cart :x x :y y))
(defun line (start end)
(make-instance 'line :start start :end end))
В случае прямоугольников точки сортируются первыми, чтобы построить верхнюю левую и нижнюю правую точки.
(defun sorted-coordinate (points coordinate)
(sort (mapcar coordinate points) #'<))
(defun rect (point-1 point-2)
(let ((points (list point-1 point-2)))
(destructuring-bind (low-x high-x) (sorted-coordinate points #'x)
(destructuring-bind (low-y high-y) (sorted-coordinate points #'y)
(make-instance 'rect
:upper-left (cart low-x high-y)
:bottom-right (cart high-x low-y))))))
Методы печати
Ваш код почти печатает формы Lisp, и, не добавляя сложности, вы можете фактически заставить метод принтера выдавать код, который может быть считан обратно для построения тех же данных. Следующие методы печатают читабельно ваших объектов с PRIN1
, как вызовы ранее определенных функций конструктора:
(defmethod print-object ((line line) stream)
(prin1 `(line ,(start line) ,(end line)) stream))
(defmethod print-object ((c cart) stream)
(prin1 `(cart ,(x c) ,(y c)) stream))
(defmethod print-object ((rect rect) stream)
(prin1 `(rect ,(upper-left rect) ,(bottom-right rect)) stream))
* +1032 * Пример
(defparameter *test-line*
(line (cart 4 3) (cart 7 5)))
Затем, вычисляя полученную строку, получаем:
CL-USER> *TEST-LINE*
=> (LINE (CART 4 3) (CART 7 5))
Это выше значение, как напечатано в REPL, которое является именно тем выражением, которое использовалось для его построения.
Граница формы в виде прямоугольника
Универсальная функция намного проще (но может быть и неправильной, поскольку прямоугольники обрабатываются по-разному):
(defgeneric containing-rect (shape))
(defmethod containing-rect ((line line))
(rect (start line) (end line)))
Например:
CL-USER> (containing-rect *test-line*)
=> (RECT (CART 4 5) (CART 7 3))