本地`macrolet`

时间:2019-04-08 19:12:13

标签: macros common-lisp

在此示例代码中

(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坐标处)的矩阵。所以(loop-over-dim mat 0) ;; => (1 4 7 10 13);至少那是目的。

但是,当尝试对其进行编译时,SBCL告诉我

  

值          ARY        不是类型          阵列

错误上方的样式警告指出loop-over-dim的参数未使用。但是它们用于macrolet的绑定中。

因此,除了样式方面的考虑之外,为什么我还会收到错误消息ARY不是数组?

我已经尝试将let*移到macrolet之外,但结果相同(错误)。

我还尝试将loop-over-dim包装在eval-when内,但没有骰子。

也许macrolet(或一般的宏)是该工作的错误工具? (请参见Hyperspec

  

[...],但是如果局部宏定义引用了在该词汇环境中可见的任何局部变量或函数绑定,则后果是不确定的。

2 个答案:

答案 0 :(得分:4)

宏在语法上起作用,因此ad绑定到符号arydim上,并且当然除了符号以外,它们都是变量宏完成工作并且扩展的代码实际运行后,对数组和数字求值。

扩展可以在编译时完成,而无需调用该函数。您应该完全松开宏并在函数中进行逻辑运行时。

答案 1 :(得分:1)

宏看到代码。您无法询问源代码,将来它将拥有什么绑定。

您可以仅调用DESCRIBE来查看a的值。 a具有符号ary作为值。 array-dimensions期望将实际数组作为参数而不是符号。

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>