https://docs.racket-lang.org/pollen/second-tutorial.html?q=pollen I am having issues with the tutorial, end of section 6.6.4. The following snippet “template.html.p” results in an error when trying to render the file “article.html” as described in the tutorial. The issue seems to be with the first case of when/splice. <html> <head> <meta charset=“UTF–8”> <title>◊(select ’h1 doc), by MB</title> <link rel=“stylesheet” type=“text/css” href=“styles.css” /> </head> <body>◊(->html doc) The current page is called ◊|here|. ◊(define prev-page (previous here)) ◊when/splice[prev-page]{The previous is <a href=“◊|prev-page|“>◊|prev-page|</a>.} ◊when/splice[(regexp-match “article” (symbol->string (next here)))]{The next is <a href=“◊|(next here)|“>◊|(next here)|</a>.} </body> </html>
Have any experienced similar? Of the three documents included in the example, arcticle.html.pmd results in a lenghty error text. Exception The application raised an exception with the message: pollen: Can’t convert procedure #<procedure:pollen-tag:here> to string @mbutterick
@jsn Do you get the same error if you try to render just this file? <html>
<head>
<meta charset="UTF-8">
<title>◊(select 'h1 doc), by MB</title>
<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body>◊(->html doc)
The current page is called ◊\|here\|.
</body>
</html>
thanks @lexi.lambda it seemed to be some issue with the index.ptree. I can’t reproduce the error after I stopped the server: raco pollen reset and raco pollen start
Do people typically use match for destructuring a list into function arguments?
Depends. Since optional arguments got support the use for that purpose has declined.
So let’s say I have (define (quadratic a b [c 0]) (calculations))
And someone had a list of arguments (define args '(1 1 5))
How would optional arguments interact with my goal?
What’s your goal?
You could either write (apply quadratic args)
or
write (define (quadratic* . args) (apply quadratic args))
and then use (quadratic* args)
.
ah I see thanks
so much simpler
Is there string interpolation in Racket? Is that something people look for?
@slack1 people sometimes use at-expressions and the formatting functions of racket/format
to do that
ah I see
greg has a blog post describing the technique: https://www.greghendershott.com/2015/08/at-expressions.html
I was slightly avoiding the racket/format
because they all seemed positional
Are at-exp
a “core” part of Racket even though it’s like a separate thing?
It’s part of the standard library, though it’s mostly used for writing Scribble docs
I see, it’s pretty nice
thanks
@slack1 I’ve been using at-expressions lately for just about everything. For example:
@michaelmmacleod Macros that expand to submodules are a bit strange. The problem is that normally, a module has its own, totally self-contained scope—it can’t refer to bindings outside itself unless they are explicitly imported with require
. But in a submodule, the syntax objects that make up the module already belong to a scope—specifically, the scope of the enclosing module.
One thing the expander could do is throw all the scoping information away, so that the bindings in the enclosing module are completely irrelevant, but it doesn’t. I can’t immediately tell you why. (Maybe there’s a reason, but I don’t know it off the top of my head.) Instead, the expander keeps the scope of everything, but just makes the bindings from the enclosing module inaccessible. This is what is happening in your program: your +
is referring to the +
in the enclosing module due to hygiene, but that binding isn’t available in the submodule. Instead, there’s a separate +
binding that comes from the racket
module language of the tester
submodule, but your +
doesn’t refer to it.
So what can you do? Well, one thing to do is to throw away all that extra scoping information yourself. You can do that using strip-context
from the syntax/strip-context
module. This program works:
#lang racket
(require (for-syntax syntax/strip-context))
(define-syntax (testing stx)
(syntax-case stx ()
[(_ form ...)
#`(module . #,(strip-context
#'(tester racket form ...)))]))
(testing (+ 2 3))
(You can’t apply strip-context
to the module
part because the module
identifier needs to be bound in the enclosing module, since that’s what initiates a submodule in the first place.)
Another thing you can do is tweak the scope of the submodule’s module language. It turns out that the expander makes the submodule’s bindings available using the scope of the identifier used as the module language, in this case the literal identifier racket
. So if you unhygienically tweak that identifier’s scope to be the same as the syntax passed into the macro, then the bindings will become accessible again:
#lang racket
(define-syntax (testing stx)
(syntax-case stx ()
[(_ form ...)
#`(module tester #,(datum->syntax stx 'racket)
form ...)]))
(testing (+ 2 3))
One final option would be to use the special #f
module language instead of using racket
at all. This is only allowed with module*
submodules, but it circumvents everything I said at the beginning of this message. A module declared with the #f
module language doesn’t get its own scope with its own set of bindings at all, and instead it just inherits the scope of the enclosing module. Therefore, if you do this, your macro will work as-is, since the outer +
binding will still be available inside the submodule:
#lang racket
(define-syntax (testing stx)
(syntax-case stx ()
[(_ form ...)
#`(module* tester #f
form ...)]))
(testing (+ 2 3))
Of course, using #f
for the module language means that the enclosing module’s bindings will always be used, instead, so if the outer module was not written in #lang racket
the submodule wouldn’t be, either. That may or may not be what you want, I don’t know.
Thanks @lexi.lambda for the detailed response! I’m going to go with the strip-context
approach, because the macro I’m writing also require
s other modules, i.e., racket/unsafe/ops
, so that form ...
can use their bindings, i.e., unsafe-fl+
.
If you use the datum->syntax
trick on the other module names (i.e. do (datum->syntax stx 'racket/unsafe/ops)
), then that approach would work for that, too. Whether that is better or worse than the approach using strip-context
, I don’t know.
Maybe @mflatt knows why submodules don’t do the context-stripping automatically, but he isn’t in this channel. I guess I’ll try in #general.
I tried using (require #,(datum->syntax stx 'racket/unsafe/ops))
, but the expander reported that the require form identifier’s binding was ambiguous.
@michaelmmacleod This code works for me, but maybe I’m overlooking something that could go wrong in bigger programs: #lang racket
(define-syntax (testing stx)
(syntax-case stx ()
[(_ form ...)
#`(module tester #,(datum->syntax stx 'racket)
(require #,(datum->syntax stx 'racket/unsafe/ops))
form ...)]))
(testing (unsafe-fx+ 2 3))
Also, I think I changed my mind. I don’t need to bother Matthew; I think I see why it makes sense that submodules don’t strip scopes automatically. Technically, ordinary modules don’t strip any scopes, either, which is what enables the horrible hack of #lang
readers sticking scopes on syntax objects to work. I don’t know if this is actually a good rationale for the current behavior, but it’s at least consistent. :stuck_out_tongue:
Oh, I think the problem is that my testing
was defined in a different file from where I used it. If you split the example up into two files, it should give you the ambiguity error. For example, #lang racket
(provide testing)
(define-syntax (testing stx)
(syntax-case stx ()
[(_ form ...)
#`(module tester #,(datum->syntax stx 'racket)
(require #,(datum->syntax stx 'racket/unsafe/ops))
form ...)]))
#lang racket
(require "testing-macro-file.rkt")
(testing (unsafe-fx+ 2 3))
Ah, I see the error now on my end, too. It’s subtle. The fact that it exists probably means you shouldn’t bother with the datum->syntax
approach, yeah.
The issue, basically, is that since you changed the binding of the racket
module language, now the require
that comes from inside the macro can’t properly access the right binding. Oops.
I think the strip-context
approach is probably less evil, anyway, so go with that. :stuck_out_tongue:
Yeah, it seems like a much nicer approach
There is a small downside to the strip-context
approach as-written that I didn’t mention, which is that DrRacket’s Check Syntax (and, by extension, racket-mode’s binding-aware features) will stop working on the form
s inside a use of the testing
macro.
But you can fix that by coupling strip-context
with syntax-local-introduce
. I don’t think doing that should cause any problems.
This version makes Check Syntax/background expansion happier: #lang racket
(require (for-syntax syntax/strip-context))
(define-syntax (testing stx)
(syntax-case stx ()
[(_ form ...)
#`(module . #,(syntax-local-introduce
(strip-context
#'(tester racket form ...))))]))
(testing (+ 2 3))
(There are still technically some very, very minor things weird about doing that, but I can’t immediately think of how to resolve them, and I doubt most people who aren’t me would even notice.)
Thanks for the syntax-local-introduce tip, now I can get my lovely binding arrows :slightly_smiling_face: