Thank you! `splice` is indeed the essential primitive here, so it's nice to see it extracted and named properly.
The difference between eval-syntax and syntax-local-eval is good to know also. I think there is a bug in the documentation (or maybe in Racket) because when I try `(syntax-local-eval #'(begin e ...) #f)` I get ..\..\Program Files\Racket-8.0.0.11\collects\racket\syntax.rkt:234:0: syntax-local-bind-syntaxes: contract violation expected: (or/c internal-definition-context? (listof internal-definition-context?)) given: #f No big deal, the empty list works, but the documentation says #f should be accepted too. > Without the whole picture of the problem you're trying to solve, it's hard to evaluate how splices compare to those alternatives, though. When choosing how to implement a macro, my first thought is "can I make define-syntax-rule work?" And if the answer is yes, then I use it -- I won't need the documentation and probably won't make a mistake. On the other end of the spectrum is syntax-parse which is way more powerful, but I will certainly need the documentation and mistakes are more likely. When I stumbled upon my splice variant, it seemed to be only slightly more complex than define-syntax-rule while enabling a much wider range of usage patterns. Or so I thought at the time, but now I'm less sure. I'll have to see how it plays out. On Monday, August 16, 2021 at 12:22:02 PM UTC-5 Michael Ballantyne wrote: > The essential primitive here seems to me to be: > > (define-syntax (splice stx) > (syntax-case stx () > [(_ e ...) > (eval-syntax #'(begin e ...))])) > > With with-quasisyntax being: > > (define-syntax-rule > (with-quasisyntax ([a b] ...) template) > (splice (with-syntax ([a b] ...) (quasisyntax template)))) > > Forms like splice appear in the metaprogramming systems of other > programming languages such as Template Haskell ( > https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/template_haskell.html) > > and Converge (https://convergepl.org/) but I haven't seen the pattern > widely used in Racket. > > I think this comes from a different philosophy. Systems like Template > Haskell think of metaprogramming as a way to automatically generate code. > From "Template Meta-programming for Haskell" ( > https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/meta-haskell.pdf > ): > The purpose of the extension is to allow programmers to compute some > parts of their program > rather than write them, and to do so seamlessly and conveniently > In Racket we generally think instead about creating either language > extensions or new sub-languages. Code generation happens to be the way we > implement the extensions or sub-languages, but the focus is on the new > syntax we are defining. If we find repeated patterns of code we start by > thinking about the language or language feature we wish was there, and then > implement that. Within those implementations we use abstractions like > syntax-parse, syntax classes, and syntax-parse template metafunctions. > > Without the whole picture of the problem you're trying to solve, it's hard > to evaluate how splices compare to those alternatives, though. > > That said, here are two alternative implementations of splice: > > (define-syntax (splice2 stx) > (syntax-case stx () > [(_ e ...) > #`(let-syntax ([m (lambda (stx) e ...)]) (m))])) > > (require (for-syntax racket/syntax)) > (define-syntax (splice3 stx) > (syntax-case stx () > [(_ e ...) > (syntax-local-eval #'(begin e ...))])) > > Whereas eval-syntax only allows access to the module-level expander > environment, these can access the local environment. That might matter if > you need to use syntax-local-value to access information from syntax > bindings. The following works with splice2 and splice3, but not splice: > > (let-syntax ([x 'foo]) > (splice3 > (displayln (syntax-local-value #'x)) > #'(void))) > > I recommend using splice3 because it avoids the intermediate expansion > step of the let-syntax . > On Friday, August 13, 2021 at 9:19:51 PM UTC-4 Ryan Kramer wrote: > >> The name `with-quasisyntax` is not very good, because it is not simply a >> quasi version of `with-syntax`. The most interesting part is that it calls >> `eval-syntax` up front. The result feels like a "universal macro" -- it can >> be used to implement both foo->assoc and assoc->foo which look like they >> would traditionally need separate macros (or one large macro that handles >> both). >> >> I am noticing that this use of `eval-syntax` can cause error messages to >> be less good, but I still think it's OK for "private" code. >> >> On Fri, Aug 13, 2021 at 2:45 PM D. Ben Knoble <[email protected]> wrote: >> >>> Ah, I'm now seeing that with-quasi implicitly #`s the body; I believe >>> with syntax-parse, #:with, and #' + template vars + #` when needed you >>> might be ok. >>> >>> -- >>> You received this message because you are subscribed to a topic in the >>> Google Groups "Racket Users" group. >>> To unsubscribe from this topic, visit >>> https://groups.google.com/d/topic/racket-users/61cQImHJfZI/unsubscribe. >>> To unsubscribe from this group and all its topics, send an email to >>> [email protected]. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/racket-users/2ede4034-80ec-49ad-9782-8883f8d47085n%40googlegroups.com >>> >>> <https://groups.google.com/d/msgid/racket-users/2ede4034-80ec-49ad-9782-8883f8d47085n%40googlegroups.com?utm_medium=email&utm_source=footer> >>> . >>> >> -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/e195ab6e-450f-497f-ad33-760232009b1cn%40googlegroups.com.

