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.

Reply via email to