How to debug macros?

I get this message:

. . ../../../../../usr/local/racket/collects/racket/private/kw.rkt:1263:25: application: not a procedure;
 expected a procedure that can be applied to arguments
  given: #<void>

It suggests to me that somewhere in my program I try to call a procedure that unfortuately isn't a procedure at all, but is void.

Of course that doesn't work.

Next step is to find where this happens.

The location in the message is of no help. It's somewhere deep within the Racket system. The backtrace that DrRacket provides never gets into anything in my code, where I presumably have the actual failed procedure call.

I study my own code, and see nothing obvious, though I believe it probably contains the error.

The program involves several macros I have written.

Being new to hygienic macros but not to Lisps, I wrote the macros as thin shells that mostly do their work in helper functions, which are in a separate module that's invoked using require for syntax.

I can understand the helper functions I've written in plain Racket, but the mysteries of the various tools for making complex macros without doing everything in phase-two helper functions still escape me. (I did try using those tools originally, but have failed to understand the details. I've read Fear of macros, and the official Racket reference documentation; there seems to be something contextual I am missing, I wish I knew what that was so I could ask it.)

I'm not asking anyone to debug my code for me.

I'd like to know is what tools there are for locating the problem. How to find out where it is going wrong.

I've already saturated suspect helper functions with printf's, both compile-time printf's and printf's generated into the macro-generated runtime.

Might there be a problem with buffering of printf so I never get to see the last output before the error messge?

I've already commented out a lot of code without losing the error message; the error has to be in the code that I still have left.

Is there some debugging tool I am missing?

Might I have to rewrite everything with the syntax-parse and other such tools so that I can get line numbers in the genreated code? I suspect, though, I need to get the line numbers within the quasiquotes in the helper functions. rather than the line numbers of the top-level macro calls.

Might I have to rewrite the helper functions in typed Racket? Calling void instead of a function sure sounds like a type. How does typed Racket interface with the macro system anyway? Do the various syntax-parse and related functions have typed equivalents? What type does typed Racket assign to a syntax object?

Is there something else I need to know?

-- hendrik

Do you have "debugging" enabled inside DrRacket? When debugging is enabled the error locations are better (but the code is slower).

For debugging macro, something you can do is to quote some suspected bodies in the macros bodies to see if you get the quoted body as result of your program/macro and no error, this means that the error was in this part of code. You can do that at any level of macro expansion until you reach the problematic macro expansion.

1 Like

No, I hadn't. I hadn't noticed the feature existed. It looks useful.

Thank you.

But when I enabled it and ran the program (which normally gets to the
error message in less than a second) it seemed to get into an endess loop.
Or was it just being slow? Stopping the execution enabled me to get
a backtrace, which consisted entirely of core that was part of the debugger.

-- hendrik

And that worked.

It helped me narrow the problem down. I suppose quoting is somewhat similar
to commenting out stuff, but quoting semed to work better than what I had been
doing.

Thank you.

It turned out I had used map to compile a list of statements, each of which
generated a void-valued expression clause that woud be used for side effects at
run-time.

And I had inserted it into a long quasiquote with ',' instead of ',@'

Result: an extra set of parentheses that caused the first void expression to be
called with the rest of the void expressions as arguments. Not useful.

-- hendrik