Return 来自泛型方法的实例列表

Return list of instances from generic method

我需要 return 通用方法中的矩形坐标列表。坐标是 class 'cart' 实例。

我用 make-instancereturn 试试

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

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

这与引用某事完全不同。

关于您的代码的一些额外提示。

这不是硬性规定,但访问器函数(通用函数)通常仅以槽命名,即 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 个点(upper-left 和 bottom-right)。

构造函数

拥有构造函数对拥有简洁易读的代码有很大帮助:

(defun cart (x y) 
  (make-instance 'cart :x x :y y))

(defun line (start end) 
  (make-instance 'line :start start :end end))

对于矩形,首先对点进行排序以构建 upper-left 和 bottom-right 点。

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

例子

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