3 ms·
Yes. Macros are evaluated at compile-time. You can put arbitrary compile-time computation in a macro. For instance, you might want to initialize a look-up table
by reikonomusha 4y ago
Yes. Macros are evaluated at compile-time. You can put arbitrary compile-time computation in a macro. For instance, you might want to initialize a look-up table at compile time. (Have you ever seen C code where it has a header file with a giant array of pre-computed constants, say, as a lookup table for values of sine? You can just generate that with a macro.)
Since macros in effect receive structured source code (basically an AST) as input, you can also do analysis of that code. For example, a macro to simplify algebraic expressions at compile-time.
Abstractions based on high-order functions also tend to allocate closures at run-time, so in practice you frequently get a performance penalty for their use.
High-order functions remove the need to use macros in some cases, but definitely don't replace all of them.
- somewhereoutth 4y agoNot original questioner, but to rephrase the question slightly: Is there anything you should do with macros that you can’t do with similar language features like higher order functions? My concern with macros is that they are completely open-ended, so you can really do anything - and if you can do anything, then the language is not usefully defining a strict enough semantic structure. As an example, see the 'hygiene problem'.
- ratzkewatzke 4y agoWithout rat-holing on "should," here's something I had to do the other day: I am providing language-level APIs for a complex web service, one in Python and one in Common Lisp. The service has dozens of operations, all of which are wrapped around a REST API that takes query strings and headers in its inputs, and produces very different outputs. Model for this is something like S3. In most languages, I have two choices: I can push the complexity to the users, making them plug the query string values into a big map or option object; or I can write dozens of functions, most of which are boilerplate. In Python I wrote dozens of functions (I obviously reused a set of central ones, but there's lots of scaffolding to do, e.g., translation of arguments from user types to strings appropriate HTTP headers). In Lisp I wrote a macro that operates on a set of query string and header inputs, and then defines a function appropriate for the user-level API. When I fix bugs in the macro, I automatically fix all of the functions. The trade-off is that the macro is itself a function that's operating at two different semantic levels (pre- and post-compilation), and it might be challenging to read for newcomers to Lisps. But this let me hide all the nasty API complexity from my users while writing substantially fewer lines of code. New additions are a single defmacro line.