top | item 11643121

A few tips for writing macros in Clojure

49 points| dwighttk | 10 years ago |blog.altometrics.com | reply

43 comments

order
[+] nonrecursive|10 years ago|reply
I'm going to be contrary and suggest that, when you're first learning a Lisp, write a macro every time you think "hey this might be a good place to write a macro" - and then try to achieve the same behavior with a function. There's no better way to learn when macros are useful and when they over-complicate things.
[+] jwr|10 years ago|reply
Excellent tips. I'd advise most inexperienced programmers (say under 10 years of lisp) to stick to tip #1. You very rarely need a macro in Clojure.
[+] jcadam|10 years ago|reply
I've recently (about two weeks ago) picked up Clojure for use on a side project after getting frustrated with trying to use Haskell for something non-trivial -- not smart enough for Haskell, apparently :D

Haven't messed with a LISP language since college but clojure has grown on me considerably. I already like it more than Scala... though I did almost immediately find myself reaching for a monad library (cats seems good so far) :) Haven't felt the need to write my own macros yet, but certainly many of the libraries I'm using (compojure) make heavy use of them.

Too bad my day job is all Java, all the time :( My continual requests to use Scala have been shot down over the last couple of years -- "We want something maintainable, where am I going to find Scala devs when you leave?" So obviously Clojure isn't going to fly :)

[+] andrewingram|10 years ago|reply
This is interesting, but also a little discouraging. Coming from a background of Python and JavaScript, and using a little bit of Elixir (which also supports macros) lately, the power of macros for defining DSLs is the main draw for me.

As an example, I've been using GraphQL quite heavily for the last 8 months, primarily with JavaScript and i've found it to be a fairly tedious experience. I tried out an Elixir GraphQL library that's heavily based on macros and was almost immediately more productive - despite not even knowing the language.

Similarly, coming up with a nice API for working with forms seems to be pretty much impossible with JavaScript. I've evaluated dozens, and not one comes close to the simplicity of Django's forms (which is only possible thanks to Python's metaclass magic).

Having sampled the power of languages with macros, I'm naturally drawn to Clojure, simply because it has a very decent JavaScript implementation. I'm sure there are other very good reasons for using the language, but right now macros are the motivation.

I'd like to understand why one would need 10 years of lisp experience before starting to author their own macros, it feels like a philosophy that's just going to stop people trying out lisp.

[+] cageface|10 years ago|reply
If it's true that you rarely need macros then isn't the awkwardness of s-expr syntax a very high price to pay just to have access to them?
[+] spion|10 years ago|reply
That seems off by about 1 order of magnitude...
[+] frou_dh|10 years ago|reply
In my home-made lisp, a macro can be an anonymous first-class value.

e.g. this is early in the stdlib and is what sets up the ability to write 'foo as a shorthand for (quote foo):

    (extend-parser "'"
                   (mac (x) (list (quote quote) x)))
Haven't yet contorted myself into wanting to map a macro value over a list, though!
[+] emidln|10 years ago|reply
This is true in emacs lisp too, although the syntax for it is a bit wonky:

    ;; increment as a macro, anonymously
    (= ((macro lambda (x) `(+ 1 ,x)) 10) 11)
[+] thomasvarney723|10 years ago|reply
I've heard it said that Clojure's macro system is most similar to Common Lisp's macro system and that Racket (and Scheme) style macros are more powerful. Can anyone compare the differing approaches?
[+] mej10|10 years ago|reply
It is more similar to CL's macro system in that it doesn't force you to write hygienic macros -- though I think CL's macro system is actually more powerful than Scheme's since it does let you write unhygienic macros.

Clojure doesn't allow user defined _reader macros_, which means it is less flexible than either CL or Scheme. Basically, you can't really define your own syntax parser in Clojure, you are limited to what the Clojure reader can already parse. In CL and Scheme you don't have this restriction.