khepin
2018-3-26 21:26:48

:wave: it’s me again! As part of a macro, I’m trying to change the name of an identifier but I’m running into issues.

(define-for-syntax (identifier-append id string)
    (datum->syntax #f (string->symbol (string-append (symbol->string (syntax->datum id)) string))))

(define-syntax (define-new stx)
    (syntax-case stx ()
        [(define-purpose name)
            (let ([new-name (identifier-append #'name "-new")])
                #'(define new-name "bob"))]))

What I want is that a call to (define-new hello) would be equivalent to (define hello-new "bob")


khepin
2018-3-26 21:27:47

the above code is what I have so far, but with that, the result I get is (define new-name "bob") instead of (define hello-new "bob")


notjack
2018-3-26 21:29:22

@khepin I think you want with-syntax instead of let - using let creates a variable at phase 1 (compile time), but the use of new-name inside your template (the #' part) is at phase 0 so it doesn’t see your let binding


notjack
2018-3-26 21:31:20

but with-syntax binds pattern variables to syntax objects, not regular variables to arbitrary values, and those pattern variables can be used in syntax templates - note that #'(foo bar baz) is equivalent to (syntax (foo bar baz))


khepin
2018-3-26 21:31:51

thanks! I’m reading through the docs on with-syntax now, this looks like what I need indeed!


notjack
2018-3-26 21:33:05

@khepin have you read greg’s Fear of Macros tutorial? I would have been lost without it when I was learning this stuff



khepin
2018-3-26 21:33:35

I have not yet!


shu--hung
2018-3-26 21:35:27

A more subtle point with ‘hygienic macros’ is you have to syntax-local-introduce on the new identifier, otherwise the new identifier will only be available inside the macro (with-syntax ([new-name (syntax-local-introduce (identifier-append #'name "-new"))]) ...


khepin
2018-3-26 21:36:12

YASS!!! that was the missing part!


khepin
2018-3-26 21:36:17

thanks to both of you!


shu--hung
2018-3-26 21:36:18

or you may use the original context: (datum->syntax id (string->symbol (string-append (symbol->string (syntax->datum id)) string)))


notjack
2018-3-26 21:36:52

you may also be interested in the format-id function


khepin
2018-3-26 21:37:14

oh, while on that, I did pass #f as the context for (datum->syntax) . But I was wondering how I would pass “whatever the context of the original id was”


notjack
2018-3-26 21:37:27

@khepin you could pass the id to the context argument directly


notjack
2018-3-26 21:37:31

it accepts syntax objects


khepin
2018-3-26 21:37:39

ooohhh


notjack
2018-3-26 21:38:38

format-id will do that too, so your macro would be:

(define-syntax (define-new stx)
    (syntax-case stx ()
        [(define-purpose name)
            (with-syntax ([new-name (format-id #'name "~a-new" #'name)])
                #'(define new-name "bob"))]))

notjack
2018-3-26 21:38:52

(disclaimer: I have only written the above code, not run it…)


shu--hung
2018-3-26 21:40:44

p.s. as a bonus: if datum->syntax gets the original source location and properties (the third and fourth argument) (datum->syntax id (string->symbol (string-append (symbol->string (syntax->datum id)) string)) id id) then hovering your mouse over “hello” and “hello-new” in DrRacket will give you a surprise :wink: