Return list of instances from generic method

时间:2019-05-31 11:54:00

标签: common-lisp evaluation quote

I need to return a coordinate list of rectangle in generic method. Coordinate is a class 'cart' instance.

I try return it with 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))

I suppose make-instance should assign an instance to something

So i get incorrect result

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

but I need an output like that

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

2 个答案:

答案 0 :(得分:6)

如果您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))

这与引用某些内容完全不同。

答案 1 :(得分:2)

关于您的代码的一些其他提示。

这不是硬性规定,但是访问器函数(它们是通用函数)通常仅以槽名命名,即x而不是get-X bad ,绝对不好样式)或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表单,并且没有增加复杂性,实际上,您可以使printer方法发出可以被读取以生成相同数据的代码。以下方法使用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))

示例

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