How can I improve my knitting?

It is worth thinking about the fact that ~> is a very unusual macro, because it is quite explicitly about pushing (“threading”) forms inside other forms. When you write

(~> foo
    (bar baz))

then the expansion is (bar foo baz), and the idea is this is just that second ~> subform with foo slipped into the middle.

Most macros do not do this, and almost none do it so mindlessly. In fact, I would even argue that most macros should not do this. Macros should be syntactic abstractions, and their users should not need to reason about them in terms of what they expand into. If that is the case, it makes sense for syntax introduced by the macro to be attributed to the macro: the macro “takes responsibility” for whatever it expands into.

What makes ~> so useful is also what makes it so unusual: it’s really just a syntactic abbreviation, and it exists purely to rearrange syntax objects. ~> neither knows nor cares about what its subforms actually mean. For this reason, the user of ~> really does want to think of the above example as precisely equivalent to if they had written (bar foo baz) directly, in the original source file, and ~> should therefore take care to honor that expectation.

Here, you are introducing a use of apply in the expansion, and you are almost certainly expecting (apply ....) to mean “a procedure application”. This means that you are in fact depending on the binding of #%app being the one from racket/base, as your expansion would fail to work correctly if (#%app apply ....) meant something else. This is really just an illustration of why macro hygiene is so important: you want your expansion to mean what it means in the module where you defined my-macro, not what it would have meant in some entirely different module with some other binding for #%app.

I don’t think I can say terribly much more without understanding what my-macro in your example is actually intended to do, but at the very least, the lexical context of the outermost syntax list (i.e. the context “on the parentheses”) should come from the template, not the input to the macro.

1 Like