Прежде всего, макросы Lisp имеют списки аргументов "деструктурирования".Это хорошая функция, которая означает, что вместо списка аргументов (rule)
и последующего его разбора с (car rule) (cadr rule) (caddr rule)
, вы можете просто создать список аргументов ((function-name column-index value))
.Таким образом, макрос ожидает список из трех элементов в качестве аргумента, и каждый элемент списка затем связывается с соответствующим символом в списке аргументов.Вы можете использовать это или нет, но обычно это более удобно.
Далее `,
на самом деле ничего не делает, потому что обратная кавычка говорит Лиспу не оценивать следующее выражение, а запятая говорит ему оценивать егов конце концов.Я думаю, что вы имели в виду просто ,(car x)
, который оценивает (car x)
.В любом случае, это не проблема, если вы используете аргументы деструктурирования.
И поскольку вы не вводите никаких новых переменных в раскрытии макроса, я не думаю, что (gensym)
необходимо в этом случае.
Таким образом, мы можем переписать макрос следующим образом:
(defmacro row-satisfies-rule ((function-name column-index value))
`(lambda (row)
(,function-name (svref row ,column-index) ,value)))
Что расширяет так, как вы хотели:
(macroexpand-1 '(row-satisfies-rule (< 1 2)))
=> (LAMBDA (ROW) (< (SVREF ROW 1) 2))
Надеюсь, это поможет!
Если вам нужно оценить аргумент, чтобы получить набор правил, то вот хороший способ сделать это:
(defmacro row-satisfies-rule (rule)
(destructuring-bind (function-name column-index value) (eval rule)
`(lambda (row)
(,function-name (svref row ,column-index) ,value))))
Вот пример:
(let ((rules '((< 1 2) (> 3 4))))
(macroexpand-1 '(row-satisfies-rule (car rules))))
=> (LAMBDA (ROW) (< (SVREF ROW 1) 2))
, как и раньше.
Если вы хотите включить в макрос row
, и он сразу даст вам ответ, вместо того, чтобы делать функцию, попробуйте это:
(defmacro row-satisfies-rule-p (row rule)
(destructuring-bind (function-name column-index value) rule
`(,function-name (svref ,row ,column-index) ,value)))
Илиесли вам нужно вычислить аргумент rule
(например, передав '(< 1 2)
или (car rules)
вместо (< 1 2)
), просто используйте (destructuring-bind (function-name column-index value) (eval rule)
На самом деле, функция кажется более подходящей, чеммакрос для того, что вы пытаетесь сделать.Просто
(defun row-satisfies-rule-p (row rule)
(destructuring-bind (function-name column-index value) rule
(funcall function-name (svref row column-index) value)))
работает так же, как макрос, и намного аккуратнее, без всякого беспорядка в обратном цитировании.
В общем, плохой стиль Lisp - использовать макросы для вещей, которыеможет быть выполнено с помощью функций.