
A few tips for writing macros in Clojure - dwighttk
http://blog.altometrics.com/2016/04/a-few-tips-for-writing-macros-in-clojure/
======
nonrecursive
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
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.

~~~
cageface
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?

~~~
reitzensteinm
I have a pet theory that someone will put a Python skin on Clojure and have
significant success with it.

~~~
SapphireSun
You can't. The reason you can use macros so easily in LISP is because of
homoiconicity:
[https://en.wikipedia.org/wiki/Homoiconicity](https://en.wikipedia.org/wiki/Homoiconicity)

Your macros will break all over the place in languages that don't have this
property.

~~~
e12e
SRFI-110 says you can^1: "Sweet-expressions are general and homoiconic, and
thus can be easily used with other constructs such as quasiquoting and macros.
In short, if a capability can be accessed using s-expressions, then they can
be accessed using sweet-expressions. Unlike Python, the notation is exactly
the same in a REPL and a file, so people can switch between a REPL and files
without issues. Fundamentally, sweet-expressions define a few additional
abbreviations for s-expressions, in much the same way that 'x is an
abbreviation for (quote x)."

[http://srfi.schemers.org/srfi-110/srfi-110.html#wisp](http://srfi.schemers.org/srfi-110/srfi-110.html#wisp)

^1 [ed: well, not "just _python_ syntax", but if you wanted that, you would be
better off using python. But python- _like_ syntax/skin is absolutely doable.
]

~~~
SapphireSun
Thanks, I learned something today. :)

------
frou_dh
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
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)

~~~
frou_dh
Oh, good. It's not a completely stupid notion then. Someone on another site
told me an anonymous macro is a contradiction in terms.

I have a diagnostics toggle (SIGUSR2) that traces what's happening with macros
for debugging. Can you think of a better way to convey it?
[http://i.imgur.com/kFzEvd6.png](http://i.imgur.com/kFzEvd6.png)

~~~
emidln
That looks like a really handy feature. I'm assuming you still have
macroexpand, macroexpand-1, and a macroexpand-all available?

I imagine that you could implement a similar feature for tracing, and if you
were careful writing the tracing code, you could then use that code for this
feature, as you could say "trace the complication e.g. (trace (eval (read
...)))" and then maybe feed in an optional list of functions to elide . This
would be super handy to have as a toggle'able feature, for both macros and
normal user code. I use clojure.tools.tracing a lot, and it's a life saver.

~~~
frou_dh
I don't have a macroexpand function and the self-imposed limit on the number
of primitive functions (32 language-related + 16 OS-related) has already been
reached! Having a whitelist for macros whose expansion should be traced would
be good as there's a lot of noise.

"Non-intrusive" tracing of any expression can be done, using an @ prefix,
based on this:

    
    
        (extend-parser
          "@"
          (mac (x)
              `(let once ,x
                    (seq (eprintln "TRACE: " once)
                         once))))

e.g.

    
    
        (def third (div 100.0 3.0))
        => TRUE
    
        (add @(mul third 2.0) third)
        TRACE: 66.66666666666667
        => 100.0
    

That's a good point that you mention tracing needing to be toggleable - it'd
be nice to be able to leave all the @s in code. I guess the macro for "@"
could either be conditionally replaced with an effective no-op, or it could
internally check for the existence of (or truthiness of) a global tracing-
enabled definition.

------
thomasvarney723
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
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.

~~~
soegaard
Scheme has historically been used as a research vehicle for macros. When the
fifth revised specification of Scheme (known as R5RS) was written there were
no consensus on the best practices for writing a system supporting unhygienic
macros.

Since then both R6RS and R7RS has support for unhygienic macros.

Note that there are two important properties of the macro systems of modern
Scheme implementations: hygiene and referential transparency. The second
property is often overlooked.

The standard syntax-rules macro system of R5RS Scheme is _hygienic_

    
    
        If a macro transformer inserts a binding for an identifier (variable or keyword), 
        the identifier will in effect be renamed throughout
        its scope to avoid conflicts with other identifiers.
    

and _referentially transparent_

    
    
        If a macro transformer inserts a free reference to 
        an identifier, the reference refers to the binding 
        that was visible where the transformer was specified,
        regardless of any local bindings that may surround
        the use of the macro.
    

The first property (automatically renaming of identifiers) is prevents common
errors. This property is _easy_ to hack around in macro systems without
automatic renaming. The macro writer simply generates a new identifier
(gensym) each time a new identifier is needed.

The second one _referential transparency_ is the killer feature. Names
inserted by a macro refers to binding where the macro is defined. This means
that the macro writer has control over the meaning of the binding of
identifiers in the expansion. In other words: a user of a macro can not by
accident rebind or assign values to identifiers inserted by a macro use.

When referential transparency is not supported, then one must be careful to
load libraries in the right order:

[http://fare.livejournal.com/146698.html](http://fare.livejournal.com/146698.html)

