Don’t write macros is a pretty good rule, but when you’re learning a language it’s quite a fun little exercise. One such exercise I like to try is this:
Write a function so that I can call system commands without having to wrap them in quotes.
So rather than doing this:
cmd([“grep”, “-rin”, “foo”, “./”])
I can do this:
cmd([grep, -rin, foo, ./])
Clojure
In lisps like clojure, the solution is very elegant, thanks to the minimal syntax, you end up with something like:
1
|
|
And the macro to do it is also pretty elegant:
1 2 3 |
|
Not too much magic (as far as macros are concerned) here. Make a unique symbol with (gensysm) to keep our macro hygienic. We syntax quote our whole list using ` to not evaluate anything unless we say so. That means we have to do some magic with our args parameter: ‘~args. ~ here means evaluate args (so we get the symbols we passed in) but then we quote with ’ so that we don’t evaluate these symbols. That’s the magic that lets us not need quotes around our arguments. The rest of the code just puts them in the right place by mapping our args list against the str function and applying it to sh. This is how you use it:
1 2 |
|
By coincidence I blogged about clojure macros almost exactly one year ago: http://mattyjwilliams.blogspot.co.uk/2012/08/another-clojure-macro-tutorial-that-no.html
Elixir
Elixir is a lovely little language I’ve been playing with recently, so naturally I wanted to try out the macros. I needed to ask a few questions on the irc channel (thanks ericmj and true_droid!), but I got it cracked:
1 2 3 4 5 6 |
|
Again, not much magic, map_join maps our list using the Macro.to_string function then joins at the end, this is done outside of the quote since we will work it out at compile time. We then pass this to System.cmd in a quote block – which means don’t evaluate this yet, that will happen when we call mcall at runtime.
1 2 |
|