chansey97
2022-3-21 20:07:28

A very beginning macro question: (define-syntax switch-log (syntax-rules () [(_ #t) (begin (define (printf/debug x . xs) (apply printf (cons x xs))) (define (printf/info x . xs) (apply printf (cons x xs))) (define (printf/warning x . xs) (apply printf (cons x xs))))] [(_ #f) (begin (define (printf/debug x . xs) (void)) (define (printf/info x . xs) (void)) (define (printf/warning x . xs) (void)))])) (switch-log #t) (printf/debug "xxx") ; <--- ERROR: printf/debug: unbound identifier But (switch-log #t) exactly macro expand to (begin (define-values (printf/debug) (lambda (x . xs) (#%app apply printf (#%app cons x xs)))) (define-values (printf/info) (lambda (x . xs) (#%app apply printf (#%app cons x xs)))) (define-values (printf/warning) (lambda (x . xs) (#%app apply printf (#%app cons x xs))))) (printf/debug "xxx") ;; xxx Need help, thanks.


ben.knoble
2022-3-21 20:19:46

Possibly a scoping/hygiene thing? That is, the scope information attached to the syntax-objects for the ids printf/debug (etc.) may not include the right scope? I’m not sure of that, though


soegaard2
2022-3-21 20:26:31

@chansey97 With syntax-rules you need to do this: (define-syntax switch-log (syntax-rules () [(_ printf/debug printf/info printf/warning #t) (begin (define (printf/debug x . xs) (apply printf (cons x xs))) (define (printf/info x . xs) (apply printf (cons x xs))) (define (printf/warning x . xs) (apply printf (cons x xs))))] [(_ printf/debug printf/info printf/warning #f) (begin (define (printf/debug x . xs) (void)) (define (printf/info x . xs) (void)) (define (printf/warning x . xs) (void)))])) (switch-log printf/debug printf/info printf/warning #t) (printf/debug "xxx")


soegaard2
2022-3-21 20:26:47

Time to try out syntax-parse !


chansey97
2022-3-21 20:58:11

Thanks all! (Although I don’t know exactly what’s going on inside.)


soegaard2
2022-3-21 20:59:41

The problem is that syntax-rules can’t introduce new identifiers where the macro is used (at the place where you write (switch-log #t). The solution is to give the identifiers to syntax-rules .


soegaard2
2022-3-21 21:00:40

The default scope for a an identifier that appears in a template is restricted to referenced to it in that template.


chansey97
2022-3-21 21:00:48

Can I understand that syntax-rules can capture identifiers, but can not create identifiers?


soegaard2
2022-3-21 21:01:28

I am not sure what you mean by “capture an identifier”.


chansey97
2022-3-21 21:04:25

(define printf/debug #f) (define printf/info #f) (define printf/warning #f) (define-syntax switch-log (syntax-rules () [(_ #t) (begin (set! printf/debug (lambda (x . xs) (apply printf (cons x xs)))) (set! printf/info (lambda (x . xs) (apply printf (cons x xs)))) (set! printf/warning (lambda (x . xs) (apply printf (cons x xs)))))] [(_ #f) (begin (set! printf/debug (lambda (x . xs) (void))) (set! printf/info (lambda (x . xs) (void))) (set! printf/warning (lambda (x . xs) (void))))])) (switch-log #t) (printf/debug "xxx") ;; xxx Then OK.


soegaard2
2022-3-21 21:04:53

This is fine due to lexical scope.


chansey97
2022-3-21 21:06:43

Yes. In this case, syntax-rules captured printf/debug. But if no printf/debug identifier in advance, syntax-rules can not create by define, unless manually pass them.


soegaard2
2022-3-21 21:09:43

Yes.


soegaard2
2022-3-21 21:11:30

The syntax-case and syntax-parse macro systems use format-id or datum->syntax to transfer the context of call to a new identifier. That is, they can make an identifier that behaves as it had been passed to the macro (as in the version I wrote above).


chansey97
2022-3-21 23:56:17

I accidentally found that struct constructor does not support keywords.