2017-06-18 52 views
0

考虑类account呼叫下一个最具体的方法是行不通的

(defclass account() 
    ((name :initarg :name :reader name) 
    (balance :initarg :balance :initform 0.00 :accessor balance) 
    (interest-rate :allocation :class :initform 0.06 
        :reader interest-rate))) 

对于这个类,我们定义了一个方法withdraw

(defmethod withdraw ((acct account) amt) 
    (if (< amt (balance acct)) 
     (decf (balance acct) amt) 
     'insufficient-funds)) 

而且,另一个类password-account,即account的子类:

(defclass password-account (account) 
    ((password :initarg :password :reader password))) 

而且,该方法withdraw,该类:

(defmethod withdraw ((acct password-account) amt pass) 
    (if (equal (password acct) pass) 
     (call-next-method acct amt) 
     'wrong-password)) 

但是,这给出了一个错误:

The generic function 
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::WITHDRAW (1)> 
takes 2 required arguments; was asked to find a method with 
specializers 
(#<STANDARD-CLASS COMMON-LISP-USER::PASSWORD-ACCOUNT> 
#1=#<SB-PCL:SYSTEM-CLASS COMMON-LISP:T> #1#) 
    [Condition of type SB-PCL::FIND-METHOD-LENGTH-MISMATCH] 
See also: 
    Common Lisp Hyperspec, FIND-METHOD [:function] 

Restarts: 
0: [RETRY] Retry SLIME REPL evaluation request. 
1: [*ABORT] Return to SLIME's top level. 
2: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {1005308033}>) 

这究竟是为什么?又是什么

被要求找到specializers的方法

这里的意思?

这里,主withdraw函数有两个参数acctamt,所以为了从一个更具体的方法,它使用的2 3个参数,而不是调用它,我们可以提供call-next-method与较不具体withdraw方法的参数。但是这仍然不起作用。
任何帮助表示赞赏。

+5

在同一个泛型函数中,不能有两个必需参数和另一个需要三个参数的方法。 CLOS不允许这样做。第一个方法定义确定所需参数的数量。在你的例子中的泛型函数有两个必需的参数,你试图用三个必需的参数来定义一个方法。这不被支持,也不被允许。 –

+0

谢谢@RainerJoswig。不支持这些方法的任何特定原因? – Mooncrater

+0

通过带参数的'call-next-method'调用下一个最具体的方法有什么意义?因为所有的方法都需要相同数量的参数。 (因此相同的参数) – Mooncrater

回答

7

全等拉姆达列出了通用功能通用功能的

方法需要有congruent拉姆达名单。语言标准描述了这个意思:Congruent Lambda-lists for all Methods of a Generic Function

正如你所看到的第一条规则说:

  • 每个拉姆达列表必须具有相同数量的必要的参数。

必需的参数告诉我们要提供的参数总是有。通用函数还允许可选的关键字和休息参数。但没有派遣这些。派遣只适用于所需的参数和所有这些。

具有相同数量的所需参数使调度更容易,并允许编译器检查具有错误数量参数的函数调用。

可选参数必须是一致的,也

还要注意的是一个通用的函数的所有方法都需要有相同数量的可选参数。请参阅标准中的第二条规则。

措辞

  • 一个参数是像
  • 参数是在呼叫提供给函数

例子在拉姆达列表中指定的变量:

(defun foo (a b) (list a b)) 

ab参数功能foo

(foo (+ 2 3) (* 4 5)) 

520是两个参数的功能foo的召唤。