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] )
答案 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))