Aqui está um que eu uso para depuração (no 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
Eu tive que lidar com uma tabela de hash rolada à mão em C ++, onde o get
método utilizou uma referência de cadeia não-const como argumento, o que significa que não posso chamá-lo com um literal. Para facilitar isso, escrevi algo como o seguinte:
#define LET(name, value, body) \
do { \
string name(value); \
body; \
assert(name == value); \
} while (false)
Embora seja improvável que algo como esse problema apareça no lisp, acho particularmente bom que você possa ter macros que não avaliam seus argumentos duas vezes, por exemplo, introduzindo uma verdadeira let-binding. (Admitido, aqui eu poderia ter contornado isso).
Também recorro ao truque horrivelmente feio de embrulhar coisas de do ... while (false)
tal maneira que você possa usá-las na parte de um if e ainda assim fazer o resto funcionar como esperado. Você não precisa disso no lisp, que é uma função de macros operando em árvores de sintaxe, em vez de seqüências de caracteres (ou sequências de token, eu acho, no caso de C e C ++), que passam por análise.
Existem algumas macros de encadeamento embutidas que podem ser usadas para reorganizar seu código, para que ele seja lido de maneira mais limpa ('encadeamento' como em 'semear o código', não paralelismo). Por exemplo:
(->> (range 6) (filter even?) (map inc) (reduce *))
Ele pega a primeira forma, (range 6)
e a torna o último argumento da próxima forma, (filter even?)
que por sua vez é o último argumento da próxima forma e assim por diante, de modo que o acima seja reescrito em
(reduce * (map inc (filter even? (range 6))))
Acho que o primeiro lê com muito mais clareza: "pegue esses dados, faça isso, depois faça isso, depois faça o outro e pronto", mas isso é subjetivo; algo que é objetivamente verdadeiro é que você leia as operações na sequência em que são executadas (ignorando a preguiça).
Há também uma variante que insere o formulário anterior como o primeiro (e não o último) argumento. Um caso de uso é aritmético:
(-> 17 (- 2) (/ 3))
Lê como "pegue 17, subtraia 2 e divida por 3".
Falando em aritmética, você pode escrever uma macro que faz análise de notação de infixo, para que você possa dizer, por exemplo, (infix (17 - 2) / 3)
e cuspirá (/ (- 17 2) 3)
qual tem a desvantagem de ser menos legível e a vantagem de ser uma expressão lisp válida. Essa é a parte de sub-linguagem DSL / dados.