Here's one I use for debugging (in 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
I had to deal with a hand-rolled hash-table in C++, where the get
method took a non-const string reference as an argument, meaning I can't call it with a literal. To make that easier to deal with, I wrote something like the following:
#define LET(name, value, body) \
do { \
string name(value); \
body; \
assert(name == value); \
} while (false)
While something like this problem is unlikely to come up in lisp, I find it particularly nice that you can have macros which don't evaluate their arguments twice, for instance by introducing a real let-binding. (Admitted, here I could have gotten around it).
I also resort to the awfully ugly hack of wrapping stuff in a do ... while (false)
such that you can use it in the then-part of an if and still have the else-part work as expected. You don't need this in lisp, which is a function of macros operating on syntax trees rather than strings (or token sequences, I think, in the case of C and C++) which then undergo parsing.
There are a few built-in threading macros which can be used to reorganize your code such that it reads more cleanly ('threading' as in 'sowing your code together', not parallelism). For example:
(->> (range 6) (filter even?) (map inc) (reduce *))
It takes the first form, (range 6)
, and makes it the last argument of the next form, (filter even?)
, which in turn is made the last argument of the next form and so on, such that the above gets rewritten into
(reduce * (map inc (filter even? (range 6))))
I think the first reads much more clearly: "take these data, do this to it, then do that, then do the other and we're done", but that's subjective; something that's objectively true is that you read the operations in the sequence they're performed (ignoring laziness).
There is also a variant which inserts the previous form as the first (rather than last) argument. One use case is arithmetic:
(-> 17 (- 2) (/ 3))
Reads as "take 17, subtract 2 and divide by 3".
Speaking of arithmetic, you can write a macro which does infix notation parsing, so that you could say e.g. (infix (17 - 2) / 3)
and it would spit out (/ (- 17 2) 3)
which has the disadvantage of being less readable and the advantage of being a valid lisp expression. That's the DSL/data sublanguage part.