Macros 本地`macrolet中未知的参数类型`

Macros 本地`macrolet中未知的参数类型`,macros,common-lisp,Macros,Common Lisp,在这个示例代码中 (defvar mat (make-array (list 5 3) :initial-contents '((1 2 3) (4 5 6) (7 8 9) (10 11

在这个示例代码中

(defvar mat (make-array (list 5 3)
                        :initial-contents '((1 2 3)
                                            (4 5 6)
                                            (7 8 9)
                                            (10 11 12)
                                            (13 14 15))))

(defun mk-idx (dims dim)
  (loop
     for i below (length dims)
     if (= i dim) collect 1
     else collect 0))

(defun loop-over-dim (ary dim)
  (macrolet ((expan (a d)
               (let* ((dims (array-dimensions a))
                      (dim-max (nth d dims))
                      (sel (mk-idx dims d))
                      (i (gensym)))
                 `(loop
                     for ,i below ,dim-max
                     collect (aref ,a ,@(substitute i 1 sel))))))
    (expan ary dim)))
我尝试访问一个矩阵,其中一维当前固定在0坐标处。因此,在昏暗的垫子0上循环;;=>1 4 7 10 13; 至少这是目的

然而,当试图编译它时,SBCL告诉我

价值 阿利 他不是那种人 排列

错误上方的样式警告表示要在dim上循环的参数未使用。但它们用于宏let的绑定

那么,除了风格方面的考虑,为什么我会得到这样一个错误,即ARY不是数组

我已经尝试将let*移到macrolet之外,但结果相同

我还试着在评估时将环包裹在昏暗的内部,但没有骰子

也许macrolet或macros通常是用于此工作的错误工具? 看,

[…]但是,如果本地宏定义引用在该词法环境中可见的任何本地变量或函数绑定,则结果是未定义的


宏处理语法,因此a和d被绑定到符号ary和dim,当然,这些符号将是变量,在宏完成其工作并且扩展代码实际运行后,这些变量将计算为数组和数字


在调用函数之前,可以在编译时进行扩展。您应该完全释放macrolet,并在函数中执行逻辑运行时

宏在语法上工作,因此a和d被绑定到符号ary和dim,当然,这些符号将是变量,在宏完成其工作并且扩展代码实际运行后,这些变量将计算为数组和数字


在调用函数之前,可以在编译时进行扩展。您应该完全释放macrolet,并在函数中执行逻辑运行时

宏可以看到代码。您不能询问源代码将来将具有什么绑定

您可以调用descripe来查看a的值。 a将符号ary作为值。数组维度要求实际数组作为参数,而不是符号

CL-USER 8 > (defun loop-over-dim (ary dim)
              (macrolet ((expan (a d)
                           (describe a)
                           nil))
                (expan ary dim)))
LOOP-OVER-DIM

CL-USER 9 > (compile 'loop-over-dim)

ARY is a SYMBOL
NAME          "ARY"
VALUE         #<unbound value>
FUNCTION      #<unbound function>
PLIST         NIL
PACKAGE       #<The COMMON-LISP-USER package, 115/256 internal, 0/4 external>

宏可以看到代码。您不能询问源代码将来将具有什么绑定

您可以调用descripe来查看a的值。 a将符号ary作为值。数组维度要求实际数组作为参数,而不是符号

CL-USER 8 > (defun loop-over-dim (ary dim)
              (macrolet ((expan (a d)
                           (describe a)
                           nil))
                (expan ary dim)))
LOOP-OVER-DIM

CL-USER 9 > (compile 'loop-over-dim)

ARY is a SYMBOL
NAME          "ARY"
VALUE         #<unbound value>
FUNCTION      #<unbound function>
PLIST         NIL
PACKAGE       #<The COMMON-LISP-USER package, 115/256 internal, 0/4 external>

检查A的参数类型。它是一个符号。为什么呢?记住:宏从代码中计算代码。好的,我认为这是正确的。因此,macrolet无法从词汇环境访问变量我认为hyperspec是这样说的:在这里,宏肯定是错误的选择吗?当宏被扩展时,没有词汇环境。编译器将展开宏,但尚未调用函数LOOP-OVER-DIM。ARY没有绑定到数组,因为函数尚未调用。请检查A的参数类型。它是一个符号。为什么呢?记住:宏从代码中计算代码。好的,我认为这是正确的。因此,macrolet无法从词汇环境访问变量我认为hyperspec是这样说的:在这里,宏肯定是错误的选择吗?当宏被扩展时,没有词汇环境。编译器将展开宏,但尚未调用函数LOOP-OVER-DIM。ARY没有绑定到数组,因为该函数尚未调用。在运行时执行该操作将需要应用,即应用'aref ARY'1 0,不是吗?但是申请有一定的限制,不是吗?@Aroob是的,但这就是申请的目的。最后一个参数的长度限制与调用中参数数量的限制相同。如果“应用”失败,如果宏正常工作,它就会失败。您可以计算CALL-ARGUMENTS-LIMIT,以查看您可能有多少个参数,并且保证至少有50个参数。在64位SBCL中,限制超过了四个五分之一,但我想50个就足以满足99%的程序员的需要。在运行时这样做将需要应用,即应用'arefary'10,不是吗?但是申请有一定的限制,不是吗?@Aroob是的,但这就是申请的目的。最后一个参数的长度限制与调用中参数数量的限制相同。如果“应用”失败,如果宏正常工作,它就会失败。您可以计算CALL-ARGUMENTS-LIMIT,以查看您可能有多少个参数,并且保证至少有50个参数。在64位SBCL中,限制超过了四个五分之一,但我想50个就足以满足99%的程序员的需要。