Аргумент не передан макросу LISP, как предполагалось - PullRequest
0 голосов
/ 17 октября 2018

Мне кажется, что я нахожусь на том же уровне, что и Базовая ошибка макроса Lisp , но когда я представляю, как должен выглядеть код в развернутом виде, я не вижу проблемы, и макроэкспанд не помогает, потому чтоон просто не хочет выводить что-либо, что я могу напечатать;macroexpand запускает для меня код?

Цитировать из связанного вопроса

Теперь при расширении макроса вызывается макрос ADD-TEST с параметром VAR, получающим значение G, символ.

Конечно, мой массив - это символ, и этим символом я хочу манипулировать, так почему возникает проблема?

Ответы [ 2 ]

0 голосов
/ 17 октября 2018

Давайте запишем, что произошло бы, если бы lisp оценивал ваш файл построчно:

(setf my-array (make-array 4 :initial-element 3))

На данный момент MY-ARRAY привязано к #(3 3 3 3)

(print my-array)

Печать #(3 3 3 3)

(setf (aref my-array 2) 5)
(print my-array)

Изменение элемента и печать #(3 3 5 3)

(defmacro set3To5 (arrnum)
  (print (arrayp arrnum))
  (print arrnum)
  (setf (aref arrnum 3) 5))

Теперь макрос SET3TO5 определен.

(set3To5 my-array)

Первый шаг здесь (о котором мы не упоминали ранее, хотя это и происходило) - это макроразложение.Компилятор знает, что SET3TO5 является макросом, поэтому он вызывает функцию макроса с MY-ARRAY (символом) в качестве аргументов.Давайте посмотрим, что происходит внутри этого макроса:

(print (arrayp arrnum))

Ну ARRNUM - это символ MY-ARRAY, поэтому он печатает NIL, хотя, возможно, и не тот поток, который вы ожидаете.

(print arrnum)

Это печатает MY-ARRAY.

(setf (aref arrnum 3) 5)

Ну ARRNUM не является массивом, поэтому у вас есть ошибка здесь.

Таким образом, мы не смогли оценить это выражение из-за расширениямакрос не удался.

Вот еще несколько вещей, которые вы могли бы сделать:

(defun set1 (arrnum)
  (print (arrayp arrnum))
  (print arrnum)
  (setf (aref arrnum 3) 5))

(defun set2 (arrnum)
  (list 'setf (list 'aref arrnum 3) 5))

(defmacro set3 (arrnum)
  (list 'setf (list 'aref arrnum 3) 5))

А теперь оцените:

CL-USER> (set1 my-array)
T
#(3 3 5 3)
5
CL-USER> my-array
#(3 3 5 5)
CL-USER> (set2 my-array)
(SETF (AREF #(3 3 5 5) 3) 5)
CL-USER> (set2 'foo)
(SETF (AREF FOO 3) 5)
CL-USER> (setf (aref my-array 3) 1)
1
CL-USER> (set3 my-array)
5
CL-USER> my-array
#(3 3 5 5)
0 голосов
/ 17 октября 2018

Короче говоря, код должен выглядеть следующим образом, чтобы у вас был массив (3 3 5 5).

(defmacro set3To5 (arrnum)
    `(print (type-of ,arrnum))
    `(setf (aref ,arrnum 3) 5)
)

GNU Common Lisp, по крайней мере, сильно заботится о разнице между`и '(это символы backtick / backquote и quote / apostrophe). Что означает обратная пометка в LISP? Оператор запятой отменяет кавычку для элемента в списке, позволяя вам подключать параметры или локальные переменные, делать ", @" для соединения в списке.

Макросы Lisp выполняют код внутри своих тел, и возвращаемый результат должен быть формой, которая затем может быть выполнена, то есть расширением макроса.

Кажется, они просто решили использовать магию, чтобы определить, как дваобе строки в кавычках превращаются в код, потому что кажется, что вам нужно будет поместить их обе в список и заключить в кавычки весь список, а затем вернуть этот список, но в этом случае он выглядит аккуратнее.

...