macros - Common Lisp 宏参数不匹配,尽管 &rest/&body

标签 macros lisp common-lisp sbcl practical-common-lisp

我一直在读 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)))))

最佳答案

您的代码存在的问题是您调用的函数的参数数量错误。该函数是使用较少元素的参数列表创建的。

看这个:

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 编译器现在假设您可以为此通用函数使用任意关键字参数,并且无法告诉您(也不是在编译时)如果您传递了错误的参数。

关于macros - Common Lisp 宏参数不匹配,尽管 &rest/&body,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15864208/

相关文章:

Lisp函数调用错误

operator-overloading - 覆盖/重载 + 运算符以对常见的 lisp 向量进行操作

c++ - 在 C/C++ 中实现 UNUSED 宏的通用编译器独立方式

c++ - 宏中的 typedef 字符

c - Ansi c 预处理器 : Can I concatenate macro name and argument into single variable name?

macros - 如何使用先前的定义重新定义宏

scheme - Lisp 程序(使用 Scheme 48 1.9 解释器)找出级数 1^3 + 2^3 + … 的总和。 + n^3

objective-c - 在 Cocoa OSX 中显示表格 View 的最少步骤

parameters - 普通口齿不清 : Working with &rest parameters

lisp - 循环打印到屏幕