5 ms·
Macros feel magical, this idea you can make your own language in no time so long as it's s-expression based, and make your own personalized vocabularies, expres
by JimmyRuska 3y ago
Macros feel magical, this idea you can make your own language in no time so long as it's s-expression based, and make your own personalized vocabularies, expression flows, fit to purpose. Personal computing at its best!
But from a working-with-other people perspective, imagine opening some code and finding random invented constructs you have to reverse engineer and step through. These days it seems everyone creates yaml or json files, and then implements some kind of declarative engine or interpreter to implement their DSL. This can be both easier to read and debug. For more complicated use cases you can tie it to a graph database that supports reasoning, instead of json/yaml
Even so, is there really something that can be done with macros that can't be done, just as elegantly, with simple state machines, or object composition style in other languages?
- memling 3y ago> But from a working-with-other people perspective, imagine opening some code and finding random invented constructs you have to reverse engineer and step through This feels just like working with another API to me. Macros can be arbitrarily complicated I suppose, but is the typical usage any more complex than learning an API? I don't really know, I guess, but my experience hasn't shown this to be that challenging. I can appreciate that programming languages are ultimately codifying a particular way to think about computation, and macros express more idiosyncratic ways of thinkingabout comouting that may not be readily understandable. I do think Racket has issues, but this isn't the first one I would cite.
- kagevf 3y ago> is there really something that can be done with macros that can't be done, just as elegantly, with simple state machines My guess would be a C# using block. I think the Java equivalent is "try with resources" but I don't remember. In Common Lisp it'd be WITH-OPEN-FILE, or a similar macro made on top of UNWIND-PROTECT ... > or object composition style builder pattern comes to mind :)
- kazinator 3y ago> finding random invented constructs you have to reverse engineer and step through Like functions and procedures? I would pray that a good number of them are compile-time code transformers that execute in the comfortable development environment, so I don't have to reverse engineer and step through them on the embedded target.
- Jtsummers 3y agoI'm very curious what you think macros are that they'd be analogous to "simple state machines". Macro expansion occurs at, well, macro expansion time which is prior to compilation (in a compiled lisp, as is the case in the context of Racket). The result of the expansion is what gets compiled. You could certainly express a state machine using macros (or with the aid of macros), perhaps even offering macro/compile time optimizations (hypothetically, you could take a regex in some form and convert it through a macro into straight code removing some runtime overhead). But macros are much, much more than "simple state machines". And I'm not sure what you mean about "object composition style", unless you're talking about the OO sense of preferring composition over inheritance. Which, again, what does that have to do with macros?
- JimmyRuska 3y agoYou can use macros to personalize your language, but for the slight overhead of run time, it's often better to use state machines or object composition style to recreate that same vocabulary. Eg somekind of cron-like event library, made from a macro (wait 6 'hr' (run './myapp')) In some OOP you could create an object style expression flow that's similar Scheduler.create(6,'hr').then(() -> system('./myapp')) Or state machine scheduler(6, 'hr', steps= [() => { system(./myapp) }, ...]); Then you customize the state machine steps with whatever, monad-like modifications are needed for that expression flow. In the end macros save you a tiny bit of typing at the expensive of limiting static analysis tooling, limiting readability since the language can be modified, and most the time the runtime way of doing it 99.9999% as fast, easier to understand, easier to debug by stepping through it. That being said I like using macros, especially in emacs. No one will ever read my dot files, and I can live in my own world.
- kazinator 3y agoThat should be a function: (wait 6 :hr (lambda () (run "./myapp"))) a macro to hide the lambda doesn't buy you much, and could be done by a macro that condenses lambda syntax: (wait 6 :hr (op run "./myapp"))
- 3y ago
- tjalfi 3y ago> Even so, is there really something that can be done with macros that can't be done, just as elegantly, with simple state machines, or object composition style in other languages? Many simple macro use cases are covered by lightweight lambda syntax, reflection, or language constructs, e.g. Go's defer, Python's with, and C#'s using. Complex macros can create DSLs or rewrite code for optimization, though. Series[0] is a Common Lisp library that rewrites lazy streams into an imperative loop. LOOP[1] and ITERATE[2] are DSLs for iteration. Schelog[3] embeds Prolog inside of Scheme. Serde[4] generates serialization code. Here are some old threads on the Lightweight Languages mailing list that discuss use cases for macros. Participants include Trevor Blackwell, Paul Graham, Dave Moon, Todd Proebsting, Guy Steele, Dan Weinreb, and many others. • Macros Make Me Mad [5] • macros vs. blocks [6] • how expressive are they [7] [0] https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node347.html https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node347.html [1] https://gigamonkeys.com/book/loop-for-black-belts.html https://gigamonkeys.com/book/loop-for-black-belts.html [2] https://iterate.common-lisp.dev/ https://iterate.common-lisp.dev/ [3] https://ds26gte.github.io/schelog/index.html https://ds26gte.github.io/schelog/index.html [4] https://serde.rs/derive.html https://serde.rs/derive.html [5] https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg02030.html https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/... [6] https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg02060.html https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/... [7] https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg02124.html https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/...
- kazinator 3y ago> But from a working-with-other people perspective There could be macro for that: (with-other-people ((bob (lookup :accounting "bob")) (alice (lookup :human-resources "alice")) ... some workflow about about last payroll .. ) ;; people are nicely disposed at the end of scope