Тип аргумента не известен в локальном `macrolet` - PullRequest
0 голосов
/ 08 апреля 2019

В этом примере кода

(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 не имеет типа ARRAY

.style-warning над ошибкой говорит о том, что аргументы loop-over-dim не используются.Но они используются в привязках macrolet.

Итак, кроме стилистических соображений, почему я получаю ошибку, что ARY не является массивом?

Я уже пытался переместить let* за пределы macrolet, но с теми же результатами (ошибка).

Я также пытался обернуть loop-over-dim внутри eval-when, но без кубиков.

Может быть, macrolet (или макросы в целом) являются (являются) инструмент (ы) для этой работы?(см. Hyperspec ,

[...], но последствия не определены, если определения локальных макросов ссылаются на любые привязки локальной переменной или функции, видимые в этой лексической среде.

)

Ответы [ 2 ]

4 голосов
/ 08 апреля 2019

Макросы работают с синтаксисом, и, таким образом, a и d связываются с символами ary и dim и, конечно, являются ничем иным, как символами, которые будут переменными, которые оценивают массивы и числа после макросавыполнил свою работу, и расширенный код фактически работает.

Расширение может быть выполнено во время компиляции задолго до вызова функции.Вы должны полностью потерять макрос и выполнить логическую среду выполнения в функции.

1 голос
/ 09 апреля 2019

Макрос видит код. Вы не можете спросить исходный код, какие у него будут привязки в будущем.

Вы можете просто вызвать 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>
...