One Racketeer

the blog of Ryan Culpepper

(blog-of ryanc@racket-lang.org)

atom

Posts

Jeremiah was a Frog

I’m rebooting my blog, previously hosted on Blogspot. I finished a conversion to Frog some time ago — there weren’t that many posts to convert, and I was already using Scribble and my now-defunct tool Scriblogify. But there was just one thing I wanted to fix about Frog’s Scribble rendering first. And then there was another thing, and so on, and in the end I wound up with something different enough to give it a new name.

new syntax template features

In Racket 7, the syntax form supports two new template subforms:

  • ~@ (“splice”) splices the result of its subtemplate (which must produce a syntax list) into the enclosing list template, and

  • ~? (“try”) chooses between alternative subtemplates depending on whether their pattern variables have “absent” values.

These features originated in syntax/parse/experimental/template: the template form was like an extended version of syntax, and ?@ and ?? were the splicing forms and the try/else template forms, respectively. The names were changed to ~@ and ~? to avoid name collisions with other libraries. In Racket 7, the old syntax/parse/experimental/template library just exports the new standard forms under the old names (that is, it exports syntax under the name template, and so on).

define vs attach

Racket’s macro system gives macros two ways of associating static (or compile-time) information with a particular name. One way is to define the name as the static information; the other is to attach the information to the already-defined name.

unprepared queries vs statement caching

Racket’s db library supports parameterized queries where the SQL is given as a string (that is, unprepared):

(query-list c "SELECT field1 FROM table WHERE field2 = ?" 17)

This is handled by an implicit call to prepare, which turns the string into a prepared statement; the prepared statement is then executed with the arguments.

The problem with this approach is that it involves two trips to the server: one to prepare and one to execute. One trip would be better. In this post I discuss two techniques for eliminating extraneous server trips. I’ve recently added one of them to Racket; the other turns out to be problematic.

lazy module loading

The Racket module system is good at managing dependencies. When you require a module, you ensure that that module is initialized before your code runs, and when the other module changes, the compiler will notice and recompile your module too. Racket even stratifies dependencies according to phase levels so you can use some modules in your macro implementations and other modules in your run-time code and the expander/compiler/linker knows what you want when. It keeps track and makes sure that everything is loaded and available when it’s supposed to be.

But sometimes you want to manage dependencies yourself. This post is about how to lazily load the implementations of functions and—with a bit of care—even macros.

definitions vs enclosing binding forms

There are two kinds of binding forms in Racket: definitions and enclosing binding forms. The scope of a binding introduced by an enclosing binding form is entirely evident: it’s one (or more) of the form’s sub-terms. For example, in

(lambda (var ...) body)

the scope of the var bindings is body. In contrast, the scope of a definition is determined by its context: the enclosing lambda body, for example, or the enclosing module—except that scope is too simple a term for how bindings work in such contexts. Enclosing binding forms are simpler and cleaner but weaker; definition forms are more powerful, but have a more complicated binding structure. Definitions also have the pleasant property of reducing rightward code drift.

syntax-parse and literals

In my last post, I talked about macros and referential auxiliary identifiers—what we usually call a macro’s “literals.” Scheme macro systems only get it half right, though, because while they compare identifiers using referential equality (i.e., using the free-identifier=? predicate), they allow literals to refer to nonexistent bindings. While the comparison is well-defined via the definition of free-identifier=?, at a higher level the idea is nonsensical.

In contrast, syntax-parse requires that every literal refer to some binding. (I’ll sometimes refer to this requirement as the is-bound property for short.) This requirement is problematic in a different way. Specifically, this property cannot be checked statically (that is, when the syntax-parse expression containing the literal is compiled).