logoalt Hacker News

sroericktoday at 3:36 PM9 repliesview on HN

I must admit - I still don't understand macros. I get that they're code that's generated at compile time. But I don't understand how that's different than a function which evaluates other functions. I guess the latter would actually be evaluated at runtime? I think I get it conceptually but I'm not sure I have the muscle memory to reach for them. Anybody here have an "ah hah!" Moment with macros?


Replies

Jtsummerstoday at 4:35 PM

If you haven't read it, I'd suggest taking a look at Paul Graham's book On Lisp [0]. He says better, and with more examples than I'd provide in a comment block, what I'd write on the subject. Jump to chapter 8 for his discussion on the topic, referring back to chapter 7 if you find the macro definitions difficult to read.

[0] https://www.paulgraham.com/onlisptext.html

efficaxtoday at 3:44 PM

Sure, macros are functions that take functions as input, and produce new functions as output. But they take the function's symbols as input and produce a new set of symbols. So a macro can extend the syntax of the language without having to modify the core language system. Anyway, what's unique about Lisp macros vs say, Rust macros, or C style preprocessors, is "homoiconicity". The data structure that a Lisp macro takes as an input, the lisp code, is the same data structure that the language uses normally (S-expressions, lists...), so writing a macro requires few new language skills compared to writing normal lisp (again, compare writing Rust macros, a dark art in comparison).

taerictoday at 4:39 PM

If it helps, https://taeric.github.io/CodeAsData.html was my attempt at exploring "code as data" and what makes lisp different here. My specific focus was more to point out that "eval" in lisp doesn't just take in a string. But I think the same general points remain.

jtara1today at 3:49 PM

You could use them to:

1. Come up with an algorithm to define an algorithm.

2. Code expansion. Instead of typing out 1000 classes that are best represented as a template of a single class, you can define a macro then use it.

3. C++ at least uses them to provide generics.

4. They let you peel back the layers of abstraction to use the language itself as an API. Useful if you want to write static analysis to do analysis on code quality, security, linting, etc.

5. Anything you can imagine, it's metaprogramming.

wild_eggtoday at 3:43 PM

There's a bit of a mental model flip to make maybe.

> they're code that's generated at compile time

They're code that generates code at compile time. Macros can actively walk the AST of the parameters they process and rewrite them completely into new shapes. That transformed AST is what then actually gets compiled.

lucyjojotoday at 4:18 PM

one way to see it is that it's a function that runs at compile time. for instance instead of dumping magic numbers/tables in a codebase you could put the code and substitute to their value at compile time.

but also it can change your code, so you get to do all the java annotation magic stuff.

timonokotoday at 6:14 PM

You do not need macros for anything. They are not the tool to "extend the language", but instructions for the compiler. And if the system does not even have a compiler, macros are useless, often incredibly stupid.

BoingBoomTschaktoday at 5:41 PM

Macros are conceptually similar to FEXPRs in that they act like functions that don't evaluate their operands and return code. The (only?) difference is that macro are all expanded before execution/runtime.

tartorantoday at 3:46 PM

[dead]