(no title)
keeeeeeeem | 3 years ago
If anyone reading this is interested in compile-time computation, you owe it to yourself to read Paul Graham (of HN)'s own work on compile time programming, "On Lisp"[0], or to take compile-time ideas to the next level, Doug Hoyte's "Let Over Lambda"[1] (LOL). Lisp languages have a long and interesting history of compile-time computation via their various macro systems, and given the first-class inclusion in most Lisps, a greater variety of ideas have been explored regarding compile-time computation.
A few interesting examples:
LOL's "Pandoric macro"[2] lets you monkey-patch closure values. It's absolutely bonkers and would almost certainly be pathological to introduce to a codebase, but it's an example of pushing the boundaries of what's possible.
Common Lisp's object system, implemented via macro[3]. To be honest, the entire Common Lisp language is a masterclass when it comes to learning about macros (I can't avoid mentioning Scheme's hygeinic macro system and Lisp-1/Lisp-2.)
A special non-Lisp shout-out goes to Rust's Diesel library for embedding SQL DDL queries into macros[4] which is not something I've personally seen before.
Clojure has a few interesting (and practical) macro libs, particularly core.async, which is an implementation of CSP (similar to Golang's channels AFAIK), it embeds perfectly into the existing language and extends its capabilities even though it's merely a library. Another interesting lib which comes to mind is Meander[5], which uses term-rewriting to provide transparent data transformations. Think declaratively interacting with data structures at compile time, and the library figuring out the best way of turning it into imperative value manipulation code.
[0] http://www.paulgraham.com/onlisp.html [1] https://letoverlambda.com/ [2] https://letoverlambda.com/index.cl/guest/chap6.html#sec_7 [3] https://mitpress.mit.edu/9780262610742/the-art-of-the-metaob... [4] https://diesel.rs/ [5] https://github.com/noprompt/meander
kazinator|3 years ago
Blatant, arbitrary compile-time evaluation (other than code transformation) is not that common in Lisp programs; which could be why such a macro wouldn't be used a lot.
For complicated, calculated constants, the Common Lisp defconstant has certain semantics that work in that space, where responsibilities are foisted onto the programmer: [A]n implementation may choose to evaluate the value-form [of defconstant] at compile time, load time, or both. Therefore, users must ensure that the initial-value can be evaluated at compile time (regardless of whether or not references to name appear in the file) and that it always evaluates to the same value.
In Common Lisp, arguably, defconstant is the mechanism of choice for blatant compile-time evaluation for actually obtaining a value from a complex expression which is thereafter treated as a constant. And its semantics isn't precise enough for the task of retrieving something from a specific environment. Using defconstant to access a file in the compilation environment won't work if the evaluation is done at load time.
In any case, defconstant looks very similar to these constant expression mechanisms that are cropping up.