Aquí hay uno que uso para depurar (en 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
Tuve que lidiar con una tabla hash enrollada a mano en C ++, donde el get
método tomó una referencia de cadena no constante como argumento, lo que significa que no puedo llamarlo con un literal. Para facilitar el tratamiento, escribí algo como lo siguiente:
#define LET(name, value, body) \
do { \
string name(value); \
body; \
assert(name == value); \
} while (false)
Si bien es poco probable que surja algo como este problema, me parece particularmente agradable que pueda tener macros que no evalúen sus argumentos dos veces, por ejemplo, introduciendo un verdadero enlace . (Admitido, aquí podría haberlo evitado).
También recurro al truco terriblemente feo de envolver cosas en un do ... while (false)
tal manera que puedas usarlo en la parte de un if y aún tener la parte de más que funcione como se esperaba. No necesita esto en lisp, que es una función de macros que operan en árboles de sintaxis en lugar de cadenas (o secuencias de tokens, creo, en el caso de C y C ++) que luego se analizan.
Hay algunas macros de subprocesamiento incorporadas que se pueden usar para reorganizar su código de modo que se lea de manera más limpia ('subprocesamiento' como en 'sembrar su código', no paralelismo). Por ejemplo:
(->> (range 6) (filter even?) (map inc) (reduce *))
Toma la primera forma, (range 6)
y lo convierte en el último argumento de la siguiente forma, (filter even?)
que a su vez se convierte en el último argumento de la siguiente forma y así sucesivamente, de modo que lo anterior se reescribe en
(reduce * (map inc (filter even? (range 6))))
Creo que el primero se lee mucho más claramente: "toma estos datos, haz esto, luego haz eso, luego haz lo otro y listo", pero eso es subjetivo; algo que es objetivamente cierto es que lees las operaciones en la secuencia en que se realizan (ignorando la pereza).
También hay una variante que inserta la forma anterior como el primer argumento (en lugar del último). Un caso de uso es la aritmética:
(-> 17 (- 2) (/ 3))
Se lee como "toma 17, resta 2 y divide entre 3".
Hablando de aritmética, puede escribir una macro que analice la notación infijada, de modo que pueda decir, por ejemplo, (infix (17 - 2) / 3)
y escupe (/ (- 17 2) 3)
cuál tiene la desventaja de ser menos legible y la ventaja de ser una expresión válida de lisp. Esa es la parte del sublenguaje DSL / datos.