Remix.run Logo
sroerick 2 hours ago

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?

BoingBoomTschak a minute ago | parent | next [-]

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.

Jtsummers an hour ago | parent | prev | next [-]

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

efficax 2 hours ago | parent | prev | next [-]

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

taeric an hour ago | parent | prev | next [-]

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.

jtara1 2 hours ago | parent | prev | next [-]

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_egg 2 hours ago | parent | prev | next [-]

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.

lucyjojo an hour ago | parent | prev | next [-]

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.

tartoran 2 hours ago | parent | prev [-]

[dead]