
Yes, I read that post. I says that I have to build the entire system, or at least the minimal system. I was wondering if there is a shortcut.

I recommend following what’s in that post

Okay.

Hi All. I have a run into a problem with a macro. I have a hunch that I am missing something simple. In short I want references to undefined variables to evaluate to false. This macro is defined in the file “top.rkt”. The macro seems to work, but when I use it in the context I need, it doesn’t.

The example is here:


@soegaard2 To be clear, you’re trying to evaluate the descriptor as an expression at phase 1, and you want an unbound reference to produce #f
?

Normally the way to do something like that is to, instead of storing the static information in a phase 1 definition, store it in a phase 0 define-syntax
definition, then look it up later with syntax-local-value
. Is there a reason you can’t do that here?

What’s the difference between a phase 1 definition and a phase 0 define-syntax ?

Every definition has two parts: the bound identifier and the expression on the RHS. An ordinary define
binds its identifier in the current phase to an expression evaluated in that same phase. This is true whatever phase the define
lives in: both the binding and the expression are just shifted to some other phase. But define-syntax
is special: it binds an identifier in the current phase to an expression evaluated in the current phase + 1.

Put another way, define-syntax
implements “glue” between Racket’s different phases: it’s what connects the binding environment of phase 0 to the value environment at phase 1.

It’s generally advantageous to put your bindings in phase 0 because they will behave in ways that users generally expect: if they declare a new record in a local scope, things will just work so long as all the bindings are defined at phase 0 (even if an outer binding is shadowed). The same is not true if you try to create a binding at phase 1, since this program is illegal: (let ()
(begin-for-syntax ; not allowed here!
(define x 1))
(void))

I think you might be right, that define-syntax and syntax-local-value is the way to go. But nevertheless, here is the thought process I followed:

Let’s say we have defined a sprite record: (define-record sprite (x y))

Then we create an instance: (define ball (sprite 11 12))

ball now lives at phase 0, but when ball.x is to be transformed into (sprite-x ball) that will happen at phase 1

thus the type of ball should be stored at phase 1

Hence an ball:type defined at phase 1 makes sense.

That does make sense, intuitively. :)

But I think one way to think about this is that Racket has a very rich language for manipulating bindings: you can rename them, add scopes to them, remove scopes from them, forge them out of thin air, and all sorts of other silly things.

So if you want to ensure that your phase 1 information is correlated with the phase 0 binding that the user thinks about, you need to attach the information to that binding, not to some other binding that you can correlate by hoping they’re both in scope at the same time with different names (and in this case, at different phases).

You can do this in different ways—you can use define-syntax
and syntax-local-value
, as I mentioned, but you could also use a free-id-table to stash the value—but the key is that the extra information is stored with the binding.

As for why your particular example doesn’t work, for what it’s worth, the problem is likely because (let-syntax ([#%top top]) ....)
binds #%top
inside the macro, but not in the scope of var:type
.

One thing I dislike about the syntax-local-value approach is that I can’t write (begin-for-syntax (displayln ball:type)) when debugging.

You could do (begin-for-syntax (displayln (syntax-local-value #'ball)))
instead.

That doesn’t work since syntax-local-value only works during expansion - so I need to write (let-syntax ([foo (λ (stx) (displayln (syntax-local-value #’ball:type)))]) foo)

Hmm. I suppose I could wrap that into a macro.

It works inside begin-for-syntax
as well as while a macro is being expanded.

Oh - it does! I could have sworn I already tried that.

The documentation says this: > This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised. “while a module is visited” is when begin-for-syntax
blocks are evaluated and when the RHSs of top-level define-syntaxes
are evaluated.

The error reported from syntax-local-value is worded as “syntax-local-value: not currently expanding”.

Technically, the error is not wrong, as modules are visited during expansion.

(Though it is maybe less clear than it could be.)

I made the switch to syntax-local-value and it does simplify the code. Thanks.