On Mon, Sep 9, 2019 at 2:42 AM Simon Haines <simon.hai...@con-amalgamate.net>
wrote:

> I'm still trying to figure out why my original, terrible macro behaved the
> way it did, but I suspect I'll never know. I would have wasted a lot of
> time on that awful construct. I appreciate your help, many thanks.
>

A great way to understand how your macros are (mis)behaving is to use the
macro stepper in DrRacket to walk through an expansion.

Here's your original macro again, with a slightly smaller example that
produces the same error ("a: unbound identifier in: a"):

> #lang racket
> (define-syntax hex
>   (syntax-rules ()
>     [(_ num ...)
>      (bytes
>       (let ([e (syntax-e #'num)])
>         (if (number? e) num
>             (string->number (symbol->string e) 16))) ...)]))
> (hex a)
>

The macro stepper shows that `(hex a)` expands into this:

> (bytes
>   (let ([e (syntax-e #'a)])
>     (if (number? e)
>         a
>         (string->number (symbol->string e) 16))))
>

Hopefully that makes some of the issues clear, starting with the use of `a`
in the "then" branch of your `if` expression, which is indeed an unbound
identifier.

In case you don't already know, you can write literal numbers in hex
notation in Racket, so `(bytes #xa #xb #xc #x1 #x2 #x3 #x41 #x42 #x43)`
evaluates to `#"\n\v\f\1\2\3ABC"`.

I strongly endorse using `syntax-parse` for writing macros, which gives you
good error checking and many other benefits. Here is a version of your
macro that expands to a literal byte-string, rather than an expression that
will create a byte-string at run-time:

> #lang racket
>
> (require (for-syntax syntax/parse))
>
> (define-for-syntax (int->hex n)
>   ;; treats n as though it had been written in hex
>   (let loop ([n n]
>              [place 0]
>              [acc 0])
>     (cond
>       [(= 0 n)
>        acc]
>       [else
>        (define-values [q r]
>          (quotient/remainder n 10))
>        (loop q (add1 place) (+ acc (* r (expt 16 place))))])))
>
>
> (define-syntax (hex stx)
>   (define-syntax-class hex-byte
>     #:description "hexadecimal byte"
>     #:attributes [n]
>     (pattern :exact-nonnegative-integer
>              #:attr n (int->hex (syntax-e this-syntax))
>              #:fail-when (and (not (byte? (attribute n))) this-syntax)
>              "not a byte? when interpreted as hexadecimal")
>     (pattern :id
>              #:attr n (string->number (symbol->string
>                                        (syntax-e this-syntax))
>                                       16)
>              #:fail-when (and (not (attribute n)) this-syntax)
>              "not a hexadecimal number"
>              #:fail-when (and (not (byte? (attribute n))) this-syntax)
>              "hexadecimal number is not a byte?"))
>   (syntax-parse stx
>     [(_ :hex-byte ...)
>      #`(quote #,(apply bytes (attribute n)))]))
>
> (hex a b c 1 2 3 41 42 43) ; #"\n\v\f\1\2\3ABC"
>

-Philip

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAH3z3gZ2qyHny0wka7xbAXWe6QgpD859wpWzQB0o6raQBinixw%40mail.gmail.com.

Reply via email to