Your pull request

 https://github.com/racket/racket/pull/1644

helps clarify the issue to me, and it looks like the right kind of
solution.

At Wed, 22 Mar 2017 16:50:20 -0700, Alex Knauth wrote:
> I'm having trouble writing macros that expand to uses of generics properly. 
> Depending on what I do in different instances it either "silently" fails to 
> implement the method or results in an ambiguous binding error.
> 
> (My end goal with this is to wrap macros around generics to do type-checking 
> on those parts of the program, using the method of Type Systems as Macros.)
> 
> The very simplest version of my problem is a macro that uses gen:custom-write 
> in it's own scope:
> 
> #lang agile
> 
> (define-simple-macro
>   (my-struct name [field ...] #:custom-write [method-def ...])
>   (struct name [field ...] #:methods gen:custom-write [method-def ...]))
> 
> (my-struct foo [a]
>   #:custom-write
>   [(define (write-proc this out mode)
>      (fprintf out "~v" (foo-a this)))])
> 
> The problem here is that the struct form assumes that the method definitions 
> will be in the same lexical context as the use of gen:custom-write. This can 
> be solved by using `datum->syntax` or `syntax-local-introduce`. That makes it 
> unhygienic, but that's fine so far. 
> 
> The next version of my problem is a macro that takes its own notion of a 
> generic interface and needs to expand into racket's generics.
> 
> #lang agile
> 
> (begin-for-syntax
>   (struct interface-info [internal-id]))
> 
> (define-syntax my-custom-write
>   (interface-info #'gen:custom-write))
> 
> ;; my structs specify generics using the #:my-methods keyword,
> ;; which expects an identifier bound with define-syntax to an
> ;; interface-info struct
> (define-simple-macro
>   (my-struct name [field ...] #:my-methods gen [method-def ...])
>   #:with internal-id (interface-info-internal-id (syntax-local-value #'gen))
>   (struct name [field ...] #:methods internal-id [method-def ...]))
> 
> (my-struct foo [a]
>   #:my-methods my-custom-write
>   [(define (write-proc this out mode)
>      (fprintf out "~v" (foo-a this)))])
> 
> This has the same problem, but with an added indirection. The actual 
> `gen:custom-write` identifier comes from someplace else, the innards of 
> `my-custom-write`. Because of this I can't just `datum->syntax` it or 
> `syntax-local-introduce` it, it could be imported from another file!
> 
> ;; interface-info.rkt
> #lang agile
> (begin-for-syntax
>   (provide (struct-out interface-info))
>   (struct interface-info [internal-id]))
> 
> ;; my-custom-write.rkt
> #lang agile
> (provide my-custom-write)
> (require "interface-info.rkt")
> (define-syntax my-custom-write
>   (interface-info #'gen:custom-write)) ; gen:custom-write is bound in this 
> scope
> 
> With this, using `syntax-local-introduce` on the internal id has the same 
> problem of failing to implement the method:
> 
> (define-simple-macro
>   (my-struct name [field ...] #:my-methods gen [method-def ...])
>   #:with internal-id (syntax-local-introduce
>                       (interface-info-internal-id (syntax-local-value #'gen)))
>   (struct name [field ...] #:methods internal-id [method-def ...]))
> 
> And trying to use `make-syntax-delta-introducer` results in an ambiguous 
> binding error:
> 
> (define-simple-macro
>   (my-struct name [field ...] #:my-methods gen [method-def ...])
>   #:with internal-id ((make-syntax-delta-introducer #'gen #false)
>                       (interface-info-internal-id (syntax-local-value #'gen)))
>   (struct name [field ...] #:methods internal-id [method-def ...]))
> 
> And using two deltas to remove the internal-id scopes and add the gen scopes 
> seems to work at first:
> 
> (define-simple-macro
>   (my-struct name [field ...] #:my-methods gen [method-def ...])
>   #:with internal-id (interface-info-internal-id (syntax-local-value #'gen))
>   #:with internal-id* ((make-syntax-delta-introducer #'gen #false)
>                        ((make-syntax-delta-introducer #'internal-id #false)
>                         #'internal-id
>                         'remove)
>                        'add)
>   (struct name [field ...] #:methods internal-id [method-def ...]))
> 
> Until you realize that completely destroyed the original binding of the 
> internal-id so that it fails on a simple example like:
> 
> (define gen:custom-write "I wouldn't attempt to interfere with bindings 
> within 
> other files")
> 
> (my-struct foo [a]
>   #:my-methods my-custom-write
>   [(define (write-proc this out mode)
>      (fprintf out "~v" (foo-a this)))])
> ;. my-custom-write.rkt:5:20: struct: the first argument to the #:methods 
> specification is not a name for a generic interface in: gen:custom-write
> 
> Without destroying the binding of the internal-id to gen:custom-write from 
> the 
> other file, how do I do this properly? Is the ambiguous binding error a sign 
> that I'm getting closer? Is there any other way to introduce generic 
> interfaces that would be more friendly to macros?
> 
> (By the way, my last example of defining a new gen:custom-write is not 
> contrived. It is necessary because the new definition is the typed version.)
> 
> Alex Knauth
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Racket Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
> To post to this group, send email to [email protected].
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-dev/2F051005-C8F0-4225-9CE3-08E44FEE89
> C6%40knauth.org.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-dev/20170324190820.88D3A65007F%40mail-svr1.cs.utah.edu.
For more options, visit https://groups.google.com/d/optout.

Reply via email to