3 ms·
Sibling comment provides a great resource, but I think a good place to start is explaining macros. At the end of the day, every line of code you write is some
by lvh 8y ago
Sibling comment provides a great resource, but I think a good place to start is explaining macros.
At the end of the day, every line of code you write is some data in a bespoke data format. Most programming language implementations leverage this, and academic compiler courses make you do the same work. A program lexes, parses, modifies... that data structure and eventually rewrites it to some other programming language, usually something lower level.
If you exposed that underlying structure to the programmer, you give them a lot of power! The simplest way to see this is that any time you write a highly repetitive bunch of code, wouldn't it be great if you could ... write some code that wrote the code for you? You know how to systematically express the thing you want: you can probably say it a lot more crisply in a few lines of (especially functional) programming languages.
Once you get rid of simple repetitive stuff, you realize that you can do so much more with this. You want advanced pattern matching? Sure: you can go implement it as a library. async/await? Library. Type checker? Library. New convenient way of defining functions? Library. New syntax for matrix math? Library. Et cetera :-)
People in other programming languages have figured this out too. That's why we have code generators. The difference is that code generators are far enough removed from what you're actually doing (because e.g. they're glorified string concatenation) to be quantumly less useful. Generally speaking advanced IDEs will do this sort of thing: actually parse the code you're working on and let you do fancy tricks with it. Lisp is like having that power, all of the time.
- travisoneill1 8y agoI messed around with Clojure for a couple of days to see what a Lisp is like but never got into any of the advanced features. What could I build that would illustrate the capability you are talking about?
- lvh 8y agoIt's hard for me to provide a good example without knowing some of the stuff you're in to but here's one of my favorite macros: https://github.com/lvh/caesium/blob/master/src/caesium/binding.clj#L484-L507 https://github.com/lvh/caesium/blob/master/src/caesium/bindi... It takes a symbol and figures out the name of a C function, how to most efficiently call it (with type hints for perf). If you screwed that up in one location it might have security consequences. But I _can't_ scre it up, because instead of copy pasting that code a gazillion times as I would have in Python, I just figured out what I want once and then use that functionality a gazillion times :)
- eval 8y agoAs an exercise you could do on a REPL what a macro would do. Say you have a file containing “(1 + 1)”. Reading this (using slurp and read-str) would yield a list, eval-ing this list would however fail as it’s not valid Clojure. To make it eval-able you transform the list (all the operations of the language are at your disposal as you’re just handling data) to (+ 1 1). It’s this operating on data between read and eval that macros do.