Ось такий, який я використовую для налагодження (у Clojure):
user=> (defmacro print-var [varname] `(println ~(name varname) "=" ~varname))
#'user/print-var
=> (def x (reduce * [1 2 3 4 5]))
#'user/x
=> (print-var x)
x = 120
nil
Мені довелося мати справу з розгорненою хеш-таблицею в C ++, де get
метод взяв в якості аргументу non-const посилання на рядок, тобто я не можу назвати це літералом. Щоб полегшити справу, я написав щось таке:
#define LET(name, value, body) \
do { \
string name(value); \
body; \
assert(name == value); \
} while (false)
Хоча щось подібне до цієї проблеми навряд чи вийде напросто, я вважаю, що особливо приємно, що ви можете мати макроси, які не оцінюють їхні аргументи двічі, наприклад, вводячи справжню прив'язку. (Зізнаюся, тут я міг би обійтись).
Я також вдаюсь до жахливого потворного загортання речей у do ... while (false)
таке, що ви можете використовувати його в тодішній частині, якщо і все-таки мати роботу іншої частини, як очікувалося. Це вам не потрібно в Lisp, що є функцією макросів, що працюють на синтаксичних деревах, а не рядків (або послідовностей лексеми, я думаю, у випадку C і C ++), які потім проходять розбір.
Існує кілька вбудованих макросів для нарізки, які можна використовувати для реорганізації вашого коду таким чином, щоб він читався більш чітко («нанизування», як при «посіванні коду разом», а не паралелізм). Наприклад:
(->> (range 6) (filter even?) (map inc) (reduce *))
Він приймає першу форму, (range 6)
і робить її останнім аргументом наступної форми, (filter even?)
яка, в свою чергу, робиться останнім аргументом наступної форми і так далі, таким чином, що вище перераховується в
(reduce * (map inc (filter even? (range 6))))
Я думаю, що перший читає набагато чіткіше: "візьміть ці дані, зробіть це, потім зробіть це, потім зробіть інше, і ми зробили", але це суб'єктивно; Що об'єктивно вірно, це те, що ви читаєте операції в послідовності, яку вони виконують (ігноруючи лінь).
Існує також варіант, який вставляє попередню форму як перший (а не останній) аргумент. Один випадок використання є арифметичним:
(-> 17 (- 2) (/ 3))
Читається як "взяти 17, відняти 2 і ділити на 3".
Якщо говорити про арифметику, ви можете написати макрос, який виконує розбір позначень інфіксованих нотацій, щоб ви могли сказати, наприклад, (infix (17 - 2) / 3)
і він би виплюнув, (/ (- 17 2) 3)
який має недолік у тому, щоб бути менш читабельним, а перевага в тому, що він є дійсним виразом lisp. Це частина підмовної DSL / даних.