2013-04-07 28 views
2

我一直在閱讀彼得塞貝爾的書,Practical Common Lisp,從書本上出現的順序將在線書籍編碼在一起,到目前爲止,我有一個文件依次編譯和加載每一章的代碼,這就是我遇到的問題:當我加載項目的FASL到目前爲止,我在ID3v2部分得到如下所示的警告。常見Lisp宏參數不匹配儘管&休息/&身體

我不明白參數號衝突出現在哪裏。 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)))) 
從以下

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))))) 

回答

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的關鍵字參數。

現在有幾種可能的方式來解決這個問題:

  1. 使用DEFGENERIC與您真的想使用,並確保所有的方法,按照它的參數列表定義泛型函數READ-DATA-VALUE

  2. 將所有參數放在所有方法中。在不使用它們的方法中,聲明它們是可以忽略的。

  3. 允許其他關鍵字參數&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編譯器現在假定您可以對此泛型函數使用任意關鍵字參數,並且如果您傳遞了錯誤的參數,則無法告訴您(也不在編譯時)。