
Sometimes macro errors drive me bonkers… Can someone with better eyes than me understand why: #lang racket
(require (for-syntax racket/syntax))
(define-syntax (define-feature-statistics stx)
(syntax-case stx ()
[(_ feature (event-types ...))
(with-syntax ([stats-name (format-id stx "~a-statistics" #'feature)])
#`(begin
#,@(for/list ([x (in-list (syntax->list #'(event-types ...)))])
(syntax-case x (:timed)
[event0
(with-syntax ([register-name (format-id "register-event/~a" #'event0)])
#`(define-syntax (register-name stx)
(syntax-case stx
[(_)
(record-event (make-event event0 (current-inexact-milliseconds) (void))
feature-statistics)])))]))))]))
(define-feature-statistics simulator
(sim-symbolic))
complains about an error in : regexp-match?: contract violation
expected: (or/c string? bytes? path? input-port?)
given: #<syntax:22:3 sim-symbolic>
argument position: 2nd
other arguments...:

I know I should be using syntax-parse by now but I haven’t gotten around to look into it…

also, not sure syntax-parse
would help in this situation.

I am sure the error is obvious to those living in macro-land, but for those knocking on the gate trying to come in this is a very rude way to welcome you. :slightly_smiling_face:

looks like you’re missing an argument at (with-syntax ([register-name (format-id

(format-id stx
…?

@dedbox ah, great. Thanks. I am indeed. But why is regexp-match?
being pointed to as the culprit instead of format-id
?

maybe @mflatt?


the definition of restricted-format-string
below uses a regexp to validate the format string.

@dedbox understood but the error message still leaks internal details I shouldn’t need to worry about.

Well, that’s a run-time error. I don’t see any contracts in the module.

I should separate those two comments. I meant to say, Racket is just crashing and reporting the point of error. A contract on format-id
could catch bad calls and report the call site instead.

I wonder if it’s absent for a reason. The signature looks pretty straight forward in the docs.

Quick glance, maybe suffice to change restricted-format-string?
from (regexp-match? #rx"^(?:[^~]\|~[aAn~%])*$" fmt)
to (and (string? fmt) (regexp-match? #rx"^(?:[^~]\|~[aAn~%])*$" fmt))
. format-id
is already using raise-arguments-error
instead of contract. (Might be unable to require racket/contract
because reasons like circular dependency.)

So, I fixed my macro above, thanks @dedbox. The thing create something like a struct with a few extra functions. I now need to provide to the user something like a struct-out
. I looked at the struct-out
implementation and OMG: https://github.com/racket/racket/blob/54989bddec0f854a290b427d7cc49b0105dc56a2/racket/collects/racket/private/reqprov.rkt#L978

Is there an easier way to achieve something like it?

I don’t want to re-export the struct-out
under a different name, but instead export a set of functions that are generated by the main macro.

Using ->i
i am trying to define a contract that ensures that two lists received as arguments have the same length. This seems to be the wrong way to do it since I cannot have an argument as its own dependent.

So when I do (->i ([lst1 list?] [lst2 (lst1 lst2) (and/c list? (= (length lst1) (length lst2)))] ...
it fails with ->i: lst2's contract depends on lst2's value

Try this: (->i ([a list?]
[b (a) (and/c list? (λ (b) (= (length a) (length b))))])
any)

Remember that the arguments to and/c
must be contracts. (and/c list? #t)
is a contract that expects its argument to be a list?
and be eq?
to #t
, which will never be satisfied.

it seems I need to name the range. but [out any/c]
will do even if it’s redundant.

thanks.

yes, that seems to work. Now it makes sense!

It looks like the struct-out
source is mostly argument processing. I wonder if it could be rewritten in a more transparent style.

@dedbox you could write it using syntax-parse more clearly, but as mentioned earlier, syntax-parse uses structs

I didn’t realize Rust’s type system designers were using PLT Redex.

As an exercise, I rewrote struct-out
in a more self-descriptive style. Here’s the diff: https://github.com/dedbox/racket/commit/1eb85d2fc44b7b0a442410c109d7e2d3519c3429

I required “define.rkt” for syntax and then used it to move and rename chunks of code. Not sure how safe that is, but the unit tests in racket-test-core are all passing.

Creating this was very informative. It helped me understand Racket a little better and gave me a reason to learn how to work with the Racket source.

@samth this is what I meant earlier