3 ms·
Is there anything you can do with macros that you can’t do with similar language features like higher order functions?
by shepherdjerred 4y ago
Is there anything you can do with macros that you can’t do with similar language features like higher order functions?
- mejutoco 4y agoNot OP, but the difference is you can run the code at compile time, so there is no performance penalty.
- reikonomusha 4y agoYes. 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.
- lispm 4y agoA Lisp macro sees the actual source it encloses and this source does not need to adhere to any pre-defined syntax. For example: we may want a macro which outputs the source it encloses, before execution: CL-USER 12 > (defmacro my-loop (&body things) `(progn (pprint (list :doing-loop-with ',things)) (loop ,@things))) MY-LOOP CL-USER 13 > (my-loop for i from 1 upto 3 sum (my-loop for j upto 3 sum (* i j))) (:DOING-LOOP-WITH (FOR I FROM 1 UPTO 3 SUM (MY-LOOP FOR J UPTO 3 SUM (* I J)))) (:DOING-LOOP-WITH (FOR J UPTO 3 SUM (* I J))) (:DOING-LOOP-WITH (FOR J UPTO 3 SUM (* I J))) (:DOING-LOOP-WITH (FOR J UPTO 3 SUM (* I J))) 36 A normal function can't do that, since it does not get source as an argument, but just sees the arguments values. Since a macro sees source, it can not only print it, but also simplify, transform, mutate, etc. the source.
- chriswarbo 4y agoYou might want to look at Template Haskell, which is used for macros in Haskell (a language which already makes heavy use of higher-order functions). One nice thing I've used macros for is reading and parsing files at compile-time, to bake-in data into programs. That way, the compiled programs just process stdio, without having to care about file paths, permission errors, parse errors, etc. (those all become compile errors)