Возврат списка экземпляров из универсального метода - PullRequest
2 голосов

Мне нужно вернуть список координат прямоугольника в общем методе. Координата - это экземпляр класса 'cart'.

Я пытаюсь вернуть его с make-instance

(defclass line ()
  ((start :initarg :start :accessor line-start)
   (end   :initarg :end   :accessor line-end)))

(defmethod print-object ((lin line) stream)
  (format stream "[LINE ~s ~s]"
          (line-start lin) (line-end lin)))

(defclass cart ()
  ((x :initarg :x :reader cart-x)
   (y :initarg :y :reader cart-y)))

(defmethod print-object ((c cart) stream)
  (format stream "[CART x ~d y ~d]"
          (cart-x c) (cart-y c)))

(setq lin (make-instance 'line
             :start (make-instance 'cart :x 4 :y 3)
             :end (make-instance 'cart :x 7 :y 5)))

(defgeneric containing-rect (shape))

(defmethod containing-rect ((l line))
  (let ((x1 (cart-x (line-start l)))
        (y1 (cart-y (line-start l)))  
        (x2 (cart-x (line-end l)))
        (y2 (cart-y (line-end l))))
    (cond ((= x1 x2) 
           '((make-instance 'cart :x (1- x1) :y y1)
             (make-instance 'cart :x (1+ x1) :y y1)
             (make-instance 'cart :x (1- x2) :y y2)
             (make-instance 'cart :x (1+ x2) :y y2)))
          ((= y1 y2)
           '((make-instance 'cart :x x1 :y (1- y1))
             (make-instance 'cart :x x1 :y (1+ y1))
             (make-instance 'cart :x x2 :y (1- y2))
             (make-instance 'cart :x x2 :y (1+ y2))))
          (t 
           (rect '((make-instance 'cart :x x1 :y y1)
                   (make-instance 'cart :x x1 :y y2)
                   (make-instance 'cart :x x2 :y y2)
                   (make-instance 'cart :x x2 :y y1)))))))

(print (containing-rect lin))

Полагаю, make-instance должен назначить экземпляр чему-либо

Итак, я получаю неправильный результат

((MAKE-INSTANCE 'CART :X X1 :Y Y1) (MAKE-INSTANCE 'CART :X X1 :Y Y2)
 (MAKE-INSTANCE 'CART :X X2 :Y Y2) (MAKE-INSTANCE 'CART :X X2 :Y Y1)) 

но мне нужен такой вывод

([CART x 4 y 3] [CART x 4 y 3] [CART x 4 y 3] [CART x 4 y 3])

Ответы [ 2 ]

6 голосов
/ 31 мая 2019

Если вы quote что-то, оно не оценивается.

Это:

'((make-instance 'cart :x (1- x1) :y y1)
  (make-instance 'cart :x (1+ x1) :y y1)
  (make-instance 'cart :x (1- x2) :y y2)
  (make-instance 'cart :x (1+ x2) :y y2))

- это буквенный список из четырех литеральных списков, каждый из которыхначинается с символа MAKE-INSTANCE, затем имеет список (QUOTE CART) и т. д. Это именно тот результат, который вы видите.

Кажется, вы действительно хотите это оценить.Проще всего сделать это и составить список:

(list (make-instance 'cart :x (1- x1) :y y1)
      (make-instance 'cart :x (1+ x1) :y y1)
      (make-instance 'cart :x (1- x2) :y y2)
      (make-instance 'cart :x (1+ x2) :y y2))

Это принципиально иная вещь, чем цитирование чего-либо.

3 голосов
/ 31 мая 2019

Некоторые дополнительные подсказки о вашем коде.

Классы

Не жесткое правило, но функции доступа (которые являются общими функциями) часто называют только по слоту, то есть 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))
...