Favorite macros


#1

I’m trying to learn more about macros, and would like to know about the most beautiful macros you’ve came across along your Lisp journey.


#2

I’m a fan of the threading macros -> ->> some-> as-> , etc. Once you get a hang of them, you want to use them everywhere. I think they solve one of the downsides of the Lisp syntax, by allowing to order things in the more familiar left to right order, instead of the inside out order of Lisp.

I’m a big fan of doto. It almost makes it nicer to interop with Java libs from Clojure, then from Java itself.

I also enjoy if case cond condp, when when-let if-let. Together they provide a very complete set of conditional flow controls.

loop and recur I find is a very ingenious use, to allow tail recursion at the syntax level.

I like for and doseq, and I actually wished Clojure had more list comprehension macros.

Finally, a shout out to core.async go thread and alt macros. It’s a really good example of their inherent power.


#3

The most “efficient” macro that I am aware of, considering its usefulness compared to its size:


#4

i’ve posted two related questions on quora that had interesting answers:
https://www.quora.com/What-are-some-good-examples-of-macro-generating-macros-in-Lisp
https://www.quora.com/What-are-the-most-beautiful-LISP-macros-that-you-know


#5

In my experience, really powerful macros generally aren’t beautiful (case in point), but their effects are.

Macros let you build up your language to fit your problem domain at the same time that the rest of your code fits your problem domain to your language. The result, if done with skill, is a tight, clean fit. A simple and easy to understand program with the bodies carefully buried in the backyard.

This is important, so I’ll say it again: macros don’t make your code simpler. They sequester complexity. This can make the system more reliable, because there is less surface area for error, but if you’re not careful that small patch can be a nightmare.

If you want to see macros do things you didn’t think were possible, I would recommend reading On Lisp and Let Over Lambda (ideally in that order). They’re both in Common Lisp, but the ideas translate very easily into Clojure.


#6

Another book specifically on Clojure Macros is Mastering Clojure Macros, that shows almost all use-cases of macros. I enjoyed the read.


#7

I add this one to many of my projects:

(defmacro cond-let
  "A version of `cond` that allows for `:let` terms."
  [& forms]
  {:pre [(even? (count forms))]}
  (when forms
    (let [[test-exp result-exp & more-forms] forms]
      (if (= :let test-exp)
        `(let ~result-exp
           (cond-let [email protected]))
        `(if ~test-exp
           ~result-exp
           (cond-let [email protected]))))))

It’s how I wish clojure.core/cond worked, allowing a :let in the middle (much like for).


#8

Can you show an example of usage ?


#9

#10

It exists to prevent the code from marching towards the right margin.


#11

Just read it. Nice! Indeed it stays flat and very readable. I may have some use for it…