调用下一个最具体的方法不起作用
Call to the next most specific method does not work
考虑 class 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)))
为此class,我们定义一个方法withdraw
:
(defmethod withdraw ((acct account) amt)
(if (< amt (balance acct))
(decf (balance acct) amt)
'insufficient-funds))
还有一个 class password-account
,它是 account
:
的子class
(defclass password-account (account)
((password :initarg :password :reader password )))
还有,方法withdraw
,为此class:
(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}>)
为什么会这样?
是什么意思
was asked to find a method with specializers
这里是什么意思?
这里,主要的 withdraw
函数有两个参数 acct
和 amt
,所以为了从更具体的方法调用它,它使用 3 个参数而不是 2 个,我们可以为 call-next-method
提供不太具体的 withdraw
方法的参数。但这仍然不起作用。
任何帮助表示赞赏。
泛型函数的一致 lambda 列表
泛型函数的方法需要有congruent lambda lists. The language standard describes what that means: Congruent Lambda-lists for all Methods of a Generic Function.
如您所见,第一条规则是:
- 每个 lambda 列表必须具有相同数量的必需参数。
必需参数 告诉我们必须提供哪些参数总是。通用函数还允许可选参数、关键字参数和剩余参数。但是这些都没有派遣。调度仅适用于必需的参数和所有这些参数。
具有相同数量的必需参数使分派更容易,并允许编译器检查参数数量错误的函数调用。
可选参数也需要一致
另请注意,泛型函数的所有方法都需要具有相同数量的可选参数。请参阅标准中的第二条规则。
措辞
- a parameter 类似于 lambda 列表中的命名变量
- 在函数调用中提供了一个参数
示例:
(defun foo (a b) (list a b))
a
和 b
是函数 foo
.
的 参数
(foo (+ 2 3) (* 4 5))
5
和 20
是调用函数 foo
.
的两个 参数
考虑 class 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)))
为此class,我们定义一个方法withdraw
:
(defmethod withdraw ((acct account) amt)
(if (< amt (balance acct))
(decf (balance acct) amt)
'insufficient-funds))
还有一个 class password-account
,它是 account
:
(defclass password-account (account)
((password :initarg :password :reader password )))
还有,方法withdraw
,为此class:
(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}>)
为什么会这样?
是什么意思was asked to find a method with specializers
这里是什么意思?
这里,主要的 withdraw
函数有两个参数 acct
和 amt
,所以为了从更具体的方法调用它,它使用 3 个参数而不是 2 个,我们可以为 call-next-method
提供不太具体的 withdraw
方法的参数。但这仍然不起作用。
任何帮助表示赞赏。
泛型函数的一致 lambda 列表
泛型函数的方法需要有congruent lambda lists. The language standard describes what that means: Congruent Lambda-lists for all Methods of a Generic Function.
如您所见,第一条规则是:
- 每个 lambda 列表必须具有相同数量的必需参数。
必需参数 告诉我们必须提供哪些参数总是。通用函数还允许可选参数、关键字参数和剩余参数。但是这些都没有派遣。调度仅适用于必需的参数和所有这些参数。
具有相同数量的必需参数使分派更容易,并允许编译器检查参数数量错误的函数调用。
可选参数也需要一致
另请注意,泛型函数的所有方法都需要具有相同数量的可选参数。请参阅标准中的第二条规则。
措辞
- a parameter 类似于 lambda 列表中的命名变量
- 在函数调用中提供了一个参数
示例:
(defun foo (a b) (list a b))
a
和 b
是函数 foo
.
(foo (+ 2 3) (* 4 5))
5
和 20
是调用函数 foo
.