> On Jun 8, 2016, at 4:22 PM, brendan <bren...@cannells.com> wrote:
> 
> 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.

The `(#,this-callback #,@name+fields)` within the definition of the `-encoding` 
macro is within the scope of it's own file, and the version of `#%app` in that 
scope is the normal one, not your `-#%app`. A function application in the scope 
of standard Racket will use the standard `#%app` even if it is used in a 
different place. That's a good thing.

> (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.)

That's a good solution. Within the scope of the definition (not the use, the 
definition), `#%app` is bound to racket's form, and `-#%app` is bound to your 
form, so you need to write `-#%app` by explicitly calling `(-#%app 
#,this-callback #,@name+fields)`. 

The other way to do this is to define the `-encoding` macro in a place where 
`#%app` is bound to your `-#%app`. 

You can do that in two ways. You could rename racket's `#%app` to `rkt:#%app` 
or something, and then define your application macro as `#%app` directly, or 
you could use a two-file setup like this:

;; define-lambda-app.rkt
#lang racket

(provide (rename-out [-define define]
                    [-λ λ]
                    [-#%app #%app]))

...

;; lang-test.rkt
#lang racket

(provide #%module-begin define λ #%app encoding)

(require "define-lambda-app.rkt")

(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*)])

That way, the definition of the `encoding` macro is in a scope where `#%app` is 
bound to your form instead of racket's.

> 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.
...
> 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!

It's that the implicit `#%app` within the definition of the `-encoding` macro 
is within the scope of the definition, not the place where it's used.

Alex Knauth

-- 
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.

Reply via email to