
Yeah, if I have some time I’ll see if I can put something together.

Hello everyone!)

Is it possible to disable hygiene in a macro definition? Everything looks like okay, expands okay but when I try to evaluate the entire module I get an error: “unbound identifier in module”.

All the day I struggle and suffer. Using Common Lisp or Clojure I’d solve it long time ago. (

@dmitryhertz You can use raco macro-stepper file.rkt
and press the End >>\|
button to get to your error message, then press \|< Step
to go back step by step until your error disappears. This will show you the current state of the macro expander, allowing you to see what’s going wrong with your macro.

It’s a bit hard to read at first, but you’ll soon get the grasp of it

As for hygiene, it’s built-in in Racket and allows a very powerful (alas complex at first) macro system. But they are ways to break hygiene. If you want to inject identifiers in scope, for example (thus breaking lexical scope) the prefered way is to use syntax-parameterize

I mean, there exists defmacro
but it’s a footgun and kittens will die if you use it https://docs.racket-lang.org/compatibility/defmacro.html

A simple example is the aif
macro (anaphoric if): https://github.com/jsmaniac/anaphoric/blob/master/aif.rkt

It’s better to follow @jerome.martin.dev’s advice and try to figure it out for real


Okay. I’ll try syntax-parameterize
, @jerome.martin.dev thank you!

@greg you made the great article! I mean “the fear of macros”. Thank you! :slightly_smiling_face:

Yes, greg’s article is very helpful :smile:

@dmitryhertz btw I think there’s an issue in your code, as you are using an unquote
instead of a syntax-unquote
here: #`(define (fn-id ld attr ...) ,req resp)
I think it should be #,req
, but maybe I’m wrong.

Or maybe actually no unquoting at all, since req
is a syntax variable.

@jerome.martin.dev I already removed , from ,req, I added the comma there accidentally. Anyway, the error is: ; rdn: unbound identifier in module
; context...:
; #(2290265 module) #(2290266 module ldap 0) #(2292600 macro) #(2292909 local)
; #(2292910 intdef) #(2292913 local) #(2292914 intdef) #(2292917 local)
; #(2292918 intdef) #(2292921 local) #(2292922 intdef) #(2292925 local)
; #(2292926 intdef)

“unbound identifier in module” can happen when your macro supplies some identifier, but you didn’t require
the module that provides it, where you defined the macro.

So e.g. this will give that error: #lang racket/base
(module m racket/base
(require (for-syntax racket/base
syntax/parse))
(define-syntax (s stx)
(syntax-parse stx
[_ #'get-pure-port]))
(provide s))
(require 'm)
s

But this will work: #lang racket/base
(module m racket/base
(require (for-syntax racket/base
syntax/parse))
(require net/url) ;; <============== NEW ========
(define-syntax (s stx)
(syntax-parse stx
[_ #'get-pure-port]))
(provide s))
(require 'm)
s

TL;DR: If your macro is supplying things like write-asn1/DER
then in your macro-defining file be sure to require
the modules that provide it

Not sure that’s the problem here, but it’s a mistake you can make

in his case I think rdn
stands for an attribute passed when using the macro, so I guess the macro actually compiles.

Hmm… I realized that I cannot pass attr … to syntax-parameterize

The problem is in attr … in that it can have different length in various the macro calls.

yes, you can use syntax-class
to simplify your macro. Wait a bit, I’m putting something together for you.

the issue is that you’re putting parts of the syntax in a hash to then build up the result. But using syntax-class, you can remove the hash stuff and use req.asn1-type
, req.app
..etc

> you’re putting parts of the syntax in a hash It seemed to me that it’s the wrong technique, now I used it to be able to put keys and values in random order. Okay, I’ll try to rewrite it withous this hash. :slightly_smiling_face:

This is a beginning (define-syntax (define-ldap stx)
(define-splicing-syntax-class type
(pattern (~seq #:asn1-type type:id))
(pattern (~seq) #:with type #'SomeDefaultValue))
(define-splicing-syntax-class req-expr
(pattern (~seq t:type a:app)))
(syntax-parse stx
[(_ (name:id ld attr ...)
[request re:req-expr ...]
[response resp-expr]) ;; ...rest of the macro

In short, you can declare every possible part of the request syntax, and put them together

here I declare a type
class which must be a sequence of two elements, #:asn1-type
followed by an identifier called type

it can also be an empty sequence (~seq)
, in which case type will be equal to SomeDefaultValue

then I declare a req-expr
class to be able to contain a sequence of a type
class and an app
class (not shown here)

the code is not complete, and I gotta go, but you can check out the (~seq)
documentation https://docs.racket-lang.org/syntax/stxparse-patterns.html?q=syntax%2Dparse#%28form._%28%28lib._syntax%2Fparse..rkt%29._~7eseq%29%29

to use a class, just add it after a colon :
on your macro identifiers

for example (_ name:id age:int photo:my-photo-class)

then you can use the class in your template with a dot notation: #'(define (student)
(let ([my-name name]
[my-age age])
(display photo.description)
(display photo.image)))

I tried to use define-splicing-syntax-class
when I read asn1 library sources https://github.com/rmculpepper/asn1/blob/master/asn1-lib/main.rkt So, probably it’s worth to try to use it again. )

my syntax-parse
knowledge is fairly new, other people will surely correct me :wink: You need to find a (pattern)
that allows a sequence of request “parts”. I don’t know if you need them in the right order or not.

@jerome.martin.dev it nearly works!:) I’m about completing it, I hope soon it will be working fine


Great :smile: I think you don’t need those extra syntax-parse
though

@jerome.martin.dev @greg thank you very much!:+1:

You’re welcome :slightly_smiling_face:


So, now I use #,(stx-cadr #’req.n) instead of #,(syntax-parse #’req.n [(k:keyword n) #’n]) form. Maybe there’s something better, maybe I’ll fix it in the near future.

Oh, it’s great to be able to develop some macros in Racket.

I discovered syntax-parse
and syntax-class
some time ago. I can’t go back, it’s too good :smile:

Yeah I don’t know yet how to do stuff like #'(hello my.super.deep.nested.value)

I guess it’s not possible yet

That would be cool though

If I understood it right, @greg wrote about it here at 4.3 section: http://www.greghendershott.com/fear-of-macros/all.html

I guess it’s possible to develop something like this

But probably it won’t be easy for a racketeer who doesn’t have enough experience with Racket’s metaprogramming.

For example, I spent 2–3 days to write define-ldap
macro and I’d be struggling 2–3 days more without community’s great help

Yes, the first time you try something with macros in Racket, it can be a real struggle. But when the frustration passes by, you realize you learned something valuable for the rest of your life x)

needs to update FoM to add a link to http://docs.racket-lang.org/syntax-parse-example/index.html

Sometime after I wrote that infix dot example, Racket added a reader option to produce #%dot
forms. Which might be a better way to do this if you control the reader, e.g. for your own #lang
. (But I guess maybe not for a generic macro?) http://docs.racket-lang.org/reference/reader.html?q=dot%20reader#%28part._parse-cdot%29

@mflatt If I eval a require statement for a relative module path, how would I tell Racket to require the file relative to a different directory.

By setting current-load-relative-directory
, or by building up a more absolute module path with operations like module-path-index-join

Okay thanks. I also see current-load
, and current-module-name-resolver
, where do they fit in the picture?

It almost looks to me like current-load
and current-module-name-resolver
both use the current-load-relative-directory
parameter, but I’m not sure how those two interplay, as the docs seem to imply they are both used for require
forms.


@mflatt: I’m trying to construct and evaluate a module with syntax I load from a file, such that relative requires in that syntax will be relative to the file I loaded it from. I can’t just load from a path because I want to control the #lang
independently from the file.

(This is for a test runner where I have several equivalent implementations of a language and want to run the same test file with each implementation)

Whoops: nevermind. Just realized the code I pasted didn’t have the current-load-relative-directory
parameterize around the require that finally triggers evaluation.

With that it’s fixed.

Though if there’s a better way to do this, I’d be interested.

@mflatt @michael.ballantyne Is that actually right though?

Like, if I require a.rkt
, which in tern requires b.rkt
, I would expect b.rkt
to be required relative to a.rkt
, not the file that required a.rkt
.

Oh interesting, if I just switch the (eval '(require 'a))
to (require "Desktop/a.rkt")
, and then print out the load paths with:
(begin-for-syntax
(define prev-load (current-load))
(current-load
(λ args
(displayln args)
(apply prev-load args))))
it does update the path properly.

Ah, okay. So if I make another c.rkt
file that b.rkt
requires, then you do get the right path. It seems like its just because the initial require is in an eval
.