Common lisp 公共Lisp:将对象传递给方法

Common lisp 公共Lisp:将对象传递给方法,common-lisp,Common Lisp,我对对象(类实例)的行为有问题 代码示例: (defclass game-cards () ((card-symbol :initarg :card-symbol :accessor card-symbol) (colour :initarg :colour :accessor colour))) (defvar *king-hearts* (make-instance 'game-cards

我对对象(类实例)的行为有问题

代码示例:

(defclass game-cards ()
  ((card-symbol :initarg :card-symbol :accessor card-symbol)
   (colour      :initarg :colour      :accessor colour)))

(defvar *king-hearts* (make-instance 'game-cards
                                     :card-symbol 'King
                                     :colour 'hearts))
(defvar *ace-spades*  (make-instance 'game-cards
                                     :card-symbol 'Ace
                                     :colour 'spades))

(defclass game-states ()  
  ((my-cards    :initarg :my-cards    :accessor my-cards)                                
   (other-cards :initarg :other-cards :accessor other-cards)))

(defparameter *state-1*
    (make-instance 'game-states
                   :my-cards    '(*king-hearts* *ace-spades*)
                   :other-cards ()))


(defmethod play-game ((state game-states))
  (some-job (first (my-cards state))))

(defmethod some-job ((card game-cards))
  (colour card))
当某个作业与参数列表中的游戏卡对象一起使用时,它的工作方式与我预期的一样

CL-USER>  (some-job  *king-hearts*)
HEARTS
CL-USER> 
这也适用于:

CL-USER> (first (my-cards *state-1*))
*KING-HEARTS*
CL-USER> 
当我尝试这个:

(some-job (first (my-cards *state-1*)))
我收到以下错误消息:

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::SOME-JOB (1)>
when called with arguments
  (*KING-HEARTS*).
   [Condition of type SIMPLE-ERROR]
同样的行为也会发生

错误消息现在为:

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::COLOUR (1)>
when called with arguments
  (*KING-HEARTS*).
   [Condition of type SIMPLE-ERROR]
通用函数没有适用的方法
#
当使用参数调用时
(*国王之心*)。
[简单错误类型的条件]
看来,
*king hearts*
现在并不是以某种职业和颜色来区分游戏卡的


原因是什么?感谢您的回答。

不评估引用的数据。这是一个基本的Lisp求值规则:

CL-USER 1 > pi
3.141592653589793D0

CL-USER 2 > 'pi
PI

CL-USER 3 > '(pi pi)
(PI PI)

CL-USER 4 > (list pi pi)
(3.141592653589793D0 3.141592653589793D0)

CL-USER 5 > (list 'pi 'pi)
(PI PI)
这里的
PI
是一个符号而不是数字:

CL-USER 6 > (type-of 'pi)
SYMBOL

CL-USER 7 > (type-of pi)
DOUBLE-FLOAT
CL-USER 8 > (defmethod square ((n number)) (* n n))
#<STANDARD-METHOD SQUARE NIL (NUMBER) 402005F60B>

CL-USER 9 > (square pi)
9.869604401089358D0
CL-USER 10 > (square 'pi)

Error: No applicable methods for #<STANDARD-GENERIC-FUNCTION SQUARE 4060010C1C> with args (PI)
  1 (continue) Call #<STANDARD-GENERIC-FUNCTION SQUARE 4060010C1C> again
  2 (abort) Return to top loop level 0.

Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
因此,我们可以为数字定义一种方法:

CL-USER 6 > (type-of 'pi)
SYMBOL

CL-USER 7 > (type-of pi)
DOUBLE-FLOAT
CL-USER 8 > (defmethod square ((n number)) (* n n))
#<STANDARD-METHOD SQUARE NIL (NUMBER) 402005F60B>

CL-USER 9 > (square pi)
9.869604401089358D0
CL-USER 10 > (square 'pi)

Error: No applicable methods for #<STANDARD-GENERIC-FUNCTION SQUARE 4060010C1C> with args (PI)
  1 (continue) Call #<STANDARD-GENERIC-FUNCTION SQUARE 4060010C1C> again
  2 (abort) Return to top loop level 0.

Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
如何解决您的问题:

  • 使用
    list
  • 或者使用
    SYMBOL-VALUE
    从全局变量中检索CLOS对象

后者通常意义不大。

您不是在传递对象,而是在传递符号(即变量本身)。你的问题可以简化为
(一些工作“*king hearts*)
。试试
:我的卡片(列表*king hearts**ace spades*)
@melpomene:什么是避免这种情况的正确方法?@melpomene:好的,谢谢你的工作。@Rainer Joswig谢谢你。我读过引号的含义,但没有正确理解符号和变量名之间的关系。据我所知,
”(*king hearts**ace spades*)
是一个未计算变量的列表,这意味着一个符号列表。因此,传递未在列表定义中计算的变量意味着传递符号。@Rainer Joswig您提出的第二种解决方案(使用
符号值
)的优点是,操纵符号可以在repl中使用有意义的名称玩纸牌游戏,并且可以检查某些函数是否正确工作(例如里夫卡)使用符号列表。@N.Böck:这是Lisp的双重用途:符号和列表本身就是数据。在程序中,列表是Lisp表单(->函数调用、特殊表单、宏表单)一个符号可以提供一个变量。一旦你在Lisp程序中引用它们,它们就是数据。这与许多其他编程语言不同,在这些语言中,代码和数据是不重叠的。@N.Böck:通常人们会直接使用CLOS对象,而不会为它们传递符号。@Rainer Joswig:好的,我对普通Lisp和面向对象程序都是新手ming.我将为
游戏卡
类定义一个额外的插槽,该类包含作为字符串的卡名。因此,如果需要卡名,我可以使用字符串而不是符号名。