我一直在读Peter Seibel的书,Practical Common Lisp,按照书中出现的顺序将在线书籍中的项目拼凑起来,到目前为止,我有一个编译并加载每一章的文件。代码反过来,这是我遇到问题的地方:什么时候 到目前为止,我为项目加载了FASL,我在ID3v2部分收到警告,如下所示。
我不明白参数编号冲突在哪里出现。 UNSIGNED-INTEGER
似乎得到了它的两个关键字参数。此外,在我看来,DEFINE-BINARY-TYPE
宏将接受任意数量的参数
使用&rest
/ &body
。我想知道你是否有任何提示或建议。一些相关的输出和代码如下。
任何和所有的帮助表示赞赏。
先谢谢,
; file: .../cl-playlist/id3v2.lisp
; in: DEFINE-BINARY-TYPE U1
; (BINARY-DATA:DEFINE-BINARY-TYPE ID3V2::U1
; NIL
; (ID3V2::UNSIGNED-INTEGER :BYTES 1 :BITS-PER-BYTE 8))
; ...
; ==>
; (BINARY-DATA:READ-VALUE 'ID3V2::UNSIGNED-INTEGER #:STREAM :BYTES 1
; :BITS-PER-BYTE 8)
;
; caught STYLE-WARNING:
; The function was called with six arguments, but wants exactly two.
“id3v2.lisp”的违规功能如下所示,
(define-binary-type u1 () (unsigned-integer :bytes 1 :bits-per-byte 8))
使用
(define-binary-type unsigned-integer (bytes bits-per-byte)
(:reader (in)
(loop with value = 0
for low-bit
downfrom (* bits-per-byte (1- bytes)) to 0 by bits-per-byte do
(setf (ldb (byte bits-per-byte low-bit) value) (read-byte in))
finally (return value)))
(:writer (out value)
(loop for low-bit
downfrom (* bits-per-byte (1- bytes)) to 0 by bits-per-byte
do (write-byte (ldb (byte bits-per-byte low-bit) value) out))))
来自“binary-data.lisp”
中的以下内容(defmacro define-binary-type (name (&rest args) &body spec)
; (defmacro define-binary-type (name &rest args &body spec)
(with-gensyms (type stream value)
`(progn
(defmethod read-value ((,type (eql ',name)) ,stream &key ,@args)
(declare (ignorable ,@args))
,(type-reader-body spec stream))
(defmethod write-value ((,type (eql ',name)) ,stream ,value &key ,@args)
(declare (ignorable ,@args))
,(type-writer-body spec stream value)))))
答案 0 :(得分:2)
您的代码存在的问题是您使用错误数量的参数调用函数。该函数已使用较少元素的参数列表创建。
见:
CL-USER> (defmethod foo ((a string) (b string) &key) (list a b))
STYLE-WARNING:
Implicitly creating new generic function COMMON-LISP-USER::FOO.
#<STANDARD-METHOD FOO (STRING STRING) {1005603C53}>
上面说DEFMETHOD
也创建了相应的泛型函数,因为没有。没关系。我们也可以使用DEFGENERIC
来声明泛型函数及其参数。在这里,SBCL从它看到的方法中推断出它。
该方法有两个参数。没有关键字参数。让我们从另一个带有一些假定的关键字参数的函数中调用它。
CL-USER> (defun bar (baz) (foo baz baz :k1 10))
; in: DEFUN BAR
; (FOO BAZ BAZ :K1 10)
;
; caught STYLE-WARNING:
; The function was called with four arguments, but wants exactly two.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
BAR
CL-USER>
现在SBCL告诉我们,我们用四个参数调用泛型函数,即使泛型函数只有两个参数。
在你的情况下,U1
的声明描述了一个带有两个参数的函数。 READ-DATA-VALUE
没有关键字参数。
现在有几种方法可以解决这个问题:
使用DEFGENERIC
使用您真正想要使用的参数列表来定义泛型函数READ-DATA-VALUE
,并确保所有方法都遵循它。
将所有参数放在所有方法中。在不使用它们的方法中,声明它们是可忽略的。
允许其他关键字参数&allow-other-keys允许不同的方法具有不同的关键字参数集。最好也采用DEFGENERIC
形式。
然后:
CL-USER> (defmethod foo1 ((a string) (b string) &key &allow-other-keys)
(list a b))
STYLE-WARNING:
Implicitly creating new generic function COMMON-LISP-USER::FOO1.
#<STANDARD-METHOD FOO1 (STRING STRING) {10058AC193}>
CL-USER> (defun bar1 (baz) (foo1 baz baz :k1 10))
BAR1
您可以看到SBCL不再抱怨并假设参数是关键字参数。
缺点是Lisp编译器现在假定您可以为此泛型函数使用任意关键字参数,并且如果传递错误,则无法告诉您(也不能在编译时)。