5 ms·
>Lack of macro hygiene is just peachy keen among Scheme programmers as long as you are explicit about which identifier bindings can leak into, or out of, the ma
by davexunit 10y ago
>Lack of macro hygiene is just peachy keen among Scheme programmers as long as you are explicit about which identifier bindings can leak into, or out of, the macro definition from the macro call site.
I haven't encountered a single case where I didn't prefer hygiene over an unhygienic solution.
- lmohseni 10y agoI'm not a lisp master, so please take the following with a grain of salt: One case where you'd want unhygienic capture is with anaphoric macros, which introduce a binding (usually named `it` as in english). For example, using an anaphoric if called aif, we can transform: (let ((result (big-long-calculation))) (if result (foo result))) into: (aif (big-long-calculation) (foo it)) cf: http://www.bookshelf.jp/texi/onlisp/onlisp_15.html http://www.bookshelf.jp/texi/onlisp/onlisp_15.html
- aidenn0 10y agoAnaphora have been controversial in the common lisp community as long as I have been involved. I imagine the same is true of the scheme community.
- groovy2shoes 10y agoYeah, anaphoric macros are a neat trick, a novelty. They're rarely useful in practice. Additionally, any time one would be useful in practice, you turn your anaphoric construct into a binding construct, and suddenly you have hygiene. To lift an example from @davexunit up-thread: (aif (foo) (bar it)) becomes instead (let-if (it (foo)) (bar it)) A minuscule amount of extra typing to be explicit, and now you not only have hygiene, but you can properly nest such forms and even generalize the form to multiple bindings: (let-and ((x (foo)) (y (bar))) (baz x y))
- dang 10y agoAnaphoric macros are used frequently in the HN source code, so "rarely useful in practice" strikes me as incorrect on both counts. Used well, they make code both shorter and more readable. That's a win-win. The arguments against them, by contrast, seem largely theoretical. Win-wins, a.k.a. having your cake and eating it too, are rare in programming, so those of us who think this way will choose that over theoretical purity any day. These arguments boil down to little more than personal preference and, above all, habit. Anaphoric macros are the kind of thing you like if you like that kind of thing. http://quoteinvestigator.com/2015/09/09/like-sort/ http://quoteinvestigator.com/2015/09/09/like-sort/
- groovy2shoes 10y agoTo clarify, I mean that the percentage of macros which are usefully anaphoric is small, not that any given anaphoric macro isn't useful in practice. A macro like `aif` is useful quite often in practice, but there aren't very many macros like `aif`. You're right that it's a personal preference. My own preference is to always be explicit (which also explains my relative distaste for Perl...). With my students, I'm constantly emphasizing that "programs must be written for people to read, and only incidentally for machines to execute"[1]. I feel as though explicity goes hand-in-hand with legibility, while I'll admit it's really just a matter of learning what `aif` does, the same way you have to learn what anything else does, I'd argue that a programmer who has never seen `let-if` before would be able to decipher its meaning from the context, whereas a programmer who's never encountered `aif` will be wondering `wtf`. [1]: Preface to the first edition of SICP.
- dang 10y agoOh yes, it's true that there are aren't many different anaphoric macros, though I occasionally run across a useful new one. But the core ones (in Arc: aif, awhen, aand) are useful in many places. I don't see that famous SICP as applying to this the way you do. Anaphoric macros obviously don't exist to make programs easier to execute—they're there entirely for humans to read, though obviously the humans don't agree about them. To my mind, wanting a program to be readable by someone who hasn't learned its idioms is like wanting a newspaper to be readable by someone who hasn't learned its words. Some words are easy to guess from context, and that's nice. But others require learning, especially when a text isn't in your native language, and that doesn't make them unreadable.
- davexunit 10y agoAh yes, that is a use-case. Though, if I were to implement something like that, I would add an extra set of parens around (big-long-calculation) and specify the name to bind the value to: (aif (it (big-long-calculation)) (foo it))
- groovy2shoes 10y agoYep, that's how I do it in Scheme myself, though I've called the construct `let-if` :)
- billsix 10y agoMy (soon to be published) book on "Computation At Compile-Time" would not be possible with hygienic macros, because I eval during macro expansion, thus treating the compiler as an interpreter during compile-time. https://github.com/billsix/bug https://github.com/billsix/bug
- qwertyuiop924 10y agoThat's possible with hygienic macros. It's not possible with declarative macros, especially those that don't allow explicit violation of hygiene. syntax-rules is declarative hygienic. However, syntax-case and sc-macro-transformer are imperative hygienic. They're capable of what your examples describe.