I'm writing a #lang using a custom #%app that transforms all multi-argument applications into nested unary applications. I've run into trouble where a macro (written in standard Racket but to be used in the #lang) is malfunctioning because when the expander processes the macro's output, it uses the standard #%app instead of the custom one.
Here's a minimal implementation. The first bits are pretty self-explanatory. The last part is a simplified version of the macro in question, intended to define Church encodings of variant data. #lang racket (provide #%module-begin (rename-out [-define define] [-λ λ] [-#%app #%app] [-encoding encoding])) (require syntax/parse/define (for-syntax racket/sequence)) (define-syntax (-define stx) (syntax-case stx () [(-define (name arg* ...) b0 b* ...) #'(define name (-λ (arg* ...) b0 b* ...))] [(-define name e) #'(define name e)])) (define-syntax (-λ stx) (syntax-case stx () [(-λ () b0 b* ...) #'(let () b0 b* ...)] [(-λ (arg) b0 b* ...) #'(λ (arg) b0 b* ...)] [(-λ (arg0 arg* ...) b0 b* ...) #'(λ (arg0) (-λ (arg* ...) b0 b* ...))])) (define-syntax (-#%app stx) (syntax-case stx () [(-#%app f) #'f] [(-#%app f arg) #'(f arg)] [(-#%app f arg0 arg* ...) #'(-#%app (f arg0) arg* ...)])) (define-syntax-parser -encoding [(-encoding (name:id fields:id ...) ...) (define callback-id* (generate-temporaries #'(name ...))) (define cons-defn* (for/list ([name+fields (in-syntax #'((name fields ...) ...))] [this-callback callback-id*]) #`(-define #,name+fields (-λ #,callback-id* (#,this-callback #,@name+fields))))) #`(begin #,@cons-defn*)]) This code will demonstrate the problem (with the above code in a module "lang-test.rkt"): (module demo "lang-test.rkt" (define (s x y z) (x z (y z))) (encoding (nil) (cons car cdr))) With expansion finished, the macro stepper shows the following. (module demo "lang-test.rkt" (#%module-begin (module configure-runtime '#%kernel (#%module-begin (#%require racket/runtime-config) (#%app configure '#f))) (define-values (s) (lambda (x) (lambda (y) (lambda (z) (#%app (#%app x z) (#%app y z)))))) (define-values (nil) (let-values:18 () (lambda:19 (nil1:21) (lambda:22 (cons2:24) (#%app:25 nil1:21 nil))))) (define-values:27 (cons) (lambda:28 (car) (lambda:30 (cdr) (lambda:32 (nil1:21) (lambda:34 (cons2:24) (#%app:36 cons2:24 cons car cdr)))))))) You can see that the define form for 's' expands into a properly curried application, i.e., (x z (y z)) becomes ((x z) (y z)). But the applications in the constructors do not: we get (cons2 cons car cdr) instead of (((cons2 cons) car) cdr). I can't figure out what's going on. Stepping through the transformation, I can clearly see the right #%app being added in the one case and doing its thing, and the wrong #%app being added in the other, but no indication of why. Examining lexical context information hasn't revealed any distinctions between the two cases. I thought maybe the use of generated temporaries might be the difference, but that was a dead end. If anyone can point out what I'm missing and how to fix it, I would be grateful. Thanks! (Note: I did come up with a band-aid of explicitly inserting a -#%app at the beginning of the application in the output syntax, which is sufficient in this case but probably not sustainable.) -- 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. For more options, visit https://groups.google.com/d/optout.