4 ms·
Unfortunately, I think perhaps might have come to a different conclusion if you'd tried Racket's so-called "hygienic" macros in anger. I've found them difficult
by pyb 4y ago
Unfortunately, I think perhaps might have come to a different conclusion if you'd tried Racket's so-called "hygienic" macros in anger. I've found them difficult to properly understand, not very usable in practice, and overly complex for non-trivial cases.
This is not what you'll usually read in forums, I think DEFMACRO is the better design here.
- reikonomusha 4y agoRacket's macro system is quite baroque and supports a lot of things. You don't need to use hygienic "syntax-rules" at all. Consider writing your own transformer [1], which can be an arbitrary lambda function without restriction. Or, import defmacro [2] and use that. As can be seen, Racket actually provides more power and choice in this regard, including support for Common Lisp's way. In any case, I make no claim to either being better or worse. I just think Racket is more principled in its mechanisms for defining and delivering a DSL to a user. [1] https://docs.racket-lang.org/guide/proc-macros.html https://docs.racket-lang.org/guide/proc-macros.html [2] https://docs.racket-lang.org/compatibility/defmacro.html https://docs.racket-lang.org/compatibility/defmacro.html
- pyb 4y agoAgree with "Racket is more principled..." Where I differ with you if that I'd say that Racket theorically provides more power, but the system is not tractable in practice. I suspect all large Racket programs were written by people with PhD's from Northwestern. BTW, Racket's defmacro is only partially compatible with Common Lisp defmacro. It doesn't really work. I even seem to remember (? from long ago) that it's impossible to implement a genuine CL defmacro in Racket.
- disconcision 4y ago> all large Racket programs were written by people with PhD's from Northwestern not totally wrong but i did write this https://github.com/disconcision/fructure https://github.com/disconcision/fructure with ~2 years programming experience. implementation features some nice simple define-syntax-rule macros which i maybe never wouldve managed with defmacro
- soegaard 4y agoYou are hanging out in the wrong forums :-) The `defmacro` model is "simpler", true - but it is fragile and breaks down when you want to do complicated things. Check this blog post written by someone, who knows hos Common Lisp. EVAL-WHEN considered harmful to your mental health https://fare.livejournal.com/146698.html https://fare.livejournal.com/146698.html
- Jach 4y agoMore to the point of how simple (and easy) defmacro is compared to syntax-case and syntax-rules, I like another fare post: https://fare.livejournal.com/189741.html https://fare.livejournal.com/189741.html If you're as smart as fare, it "isn't too hard to translate it". Though I concede this case could be analogous to trying to write a Doubly Linked List in Rust, it's not enough to say definitively yea or nay. So I'd more like to see a concrete case you have in mind where the tradeoffs are squarely against CL. Like, the loop macro is more complicated than any I have written myself, but you can break it down, and it's not that bad -- I think Norvig's version is pretty neat to study: https://norvig.com/paip/loop.lisp https://norvig.com/paip/loop.lisp This project (and it's not the only one!) adding C syntax to CL https://github.com/y2q-actionman/with-c-syntax https://github.com/y2q-actionman/with-c-syntax I think is more complicated than loop, and is sort of where I'd put the level of "complicated things" at that I'd like to see an example from the Scheme world that clearly shows defmacro's deficiencies on some metrics. (Fewer bugs? Easier to add new features to? Shorter code? Faster performance either at compile time or runtime or both? Easier to understand or faster to implement for people with similar levels of skill in the language?)
- soegaard 4y agoThe final `syntax-case` version: (define-syntax (nest stx) (syntax-case stx () ((nest outer ... inner) (foldr (lambda (o i) (with-syntax (((outer ...) o) (inner i)) #'(outer ... inner))) #'inner (syntax->list #'(outer ...)))))) looks fine to me. Using #` and #, and defining `reduce` one could make a version that looks like the Common Lisp implementation. Note that the `nest` form just rearranges its input - so there is no problems getting the scope of identifiers correct. That is: we are well within the comfort zone of `defmacro`. With regards to the `syntax-rules` solution: Fare refers to "when I learned Scheme" and pre-R6RS there were no `syntax-case` in the specification. In practise all implemenations did have macro systems more expressive than `syntax-rules`, but it was fun to see whether something was possible with plain `syntax-rules`.
- nathan_compton 4y agoTo each his own, obviously, but I've programmed a fair amount in CL and Scheme and vastly prefer syntax-case to defmacro. There is a little more cognitive overhead, but it all makes sense. Syntax-case macros are easier to write and read, from my point of view. And Racket has syntax-parse, which is even nicer, I seem to recall.