[racket] hygienic read-macros (was: module-level definitions vs. local definitions and how binding works)

From: Alexander D. Knauth (alexander at knauth.org)
Date: Mon Jul 28 11:08:20 EDT 2014

Well that works fine when it’s in the same module (or namespace), but when I put it in a #lang, it breaks and I get this error:
experiment-with-hygenic-reader-extensions/try-it.rkt:
#lang experiment-with-hygenic-reader-extensions
$
; g15667: unbound identifier in module in: g15667

That’s one problem with unhygienic reader extensions.  
Since you used (datum->syntax #f ‘(GENSYM …)), it eventually took on the lexical context of try-it.rkt, where the GENSYM name isn’t there.

Though strangely, if I put some lexical context on GENSYM by using (datum->syntax #f `(,#'GENSYM …)), then it gives me this error:
experiment-with-hygenic-reader-extensions-2/try-it.rkt:
#lang experiment-with-hygenic-reader-extensions-2
$
; require: namespace mismatch;
; reference to a module that is not available
;  reference phase: 0
;  referenced module: “…/experiment-with-hygenic-reader-extensions-2/lang/reader.rkt"
;  referenced phase level: 0 in: g24

https://github.com/AlexKnauth/experiment-with-hygenic-reader-extensions

On Jul 28, 2014, at 3:49 AM, Roman Klochkov <kalimehtar at mail.ru> wrote:

> 
> You may use such macro for making hygienic read-macros
> 
> (define-syntax (make-reader stx)
>    (syntax-case stx ()
>      [(_ NAME BODY ...)
>       (with-syntax ([GENSYM (datum->syntax stx (gensym))])
>         #'(begin
>             (define-syntax (GENSYM stx)
>               (syntax-case stx ()
>                 [(_ in src line col pos) BODY ...]))
>             (provide GENSYM)
>             (define NAME
>               (case-lambda
>                 [(ch in)
>                  (datum->syntax #f '(GENSYM in #f #f #f #f))]
>                 [(ch in src line col pos)
>                  (datum->syntax #f '(GENSYM in src line col pos))]))))]))
> 
> Usage example:
> (make-reader read-dollar
>               #'(lambda (x) x))
> 
> (current-readtable 
>   (make-readtable (current-readtable)
>                   #\$ 'terminating-macro read-dollar))
> 
> Test:
>> $
> #<procedure>
>> (let ([lambda 1]) $)
> #<procedure>
> 
> All works just fine
> 
> Sun, 27 Jul 2014 20:10:48 -0400 от "Alexander D. Knauth" <alexander at knauth.org>:
>> It seems like “hygienic reader extensions” still work when a module-level definition conflicts with it, but it seems like if it’s a local binding the local binding overrides the one in the reader extension.  
>> 
>> For example:
>> #lang rackjure
>> ;; this works:
>> (define lambda "module-level-whatever")
>> #λ(void %1) ; #<procedure>
>> ;; this doesn't work
>> (let ([lambda "local-whatever"]
>>       [%1 void]
>>       [define-syntax void]
>>       [% void])
>>   #λ(void %1)) ; application: not a procedure;
>> ;              ;   expected a procedure that can be applied to arguments
>> ;              ;   given: "local-whatever"
>> ;              ;   arguments…:
>> 
>> Why does it work at the module-level and not within a let? 
>> 
>> Is this a bug, or should reader extensions not be used this way, or what?  
>> 
>> What’s going on here?
>> 
>> 
>> ____________________
>>   Racket Users list:
>>    http://lists.racket-lang.org/users
>> 
> 
> 
> -- 
> Roman Klochkov



Posted on the users mailing list.