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

From: Roman Klochkov (kalimehtar at mail.ru)
Date: Mon Jul 28 11:41:01 EDT 2014

 I tried to make it with module
(module m racket
  (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))]))))]))
  (make-reader read-dollar
               #'(lambda (x) x))
  
  (current-readtable 
   (make-readtable (current-readtable)
                   #\$ 'terminating-macro read-dollar)))

(require 'm)

Works just fine

I'm not very proficient with lang, but you should require module with `make-reader' to you last module.

I installed your package via `raco pkg install git://github.com/AlexKnauth/experiment-with-hygenic-reader-extensions', but

$ /usr/racket/bin/racket try-it.rkt
default-load-handler: cannot open module file
  module path: experiment-with-hygenic-reader-extensions/lang/reader
  path: /home/monk/.racket/6.0.1/pkgs/experiment-with-hygenic-reader-extensions/experiment-with-hygenic-reader-extensions/lang/reader.rkt
  system error: No such file or directory; errno=2

Maybe something wrong.

I think you should add (require (submod experiment-with-hygenic-reader-extensions/lang/reader reader)) to try-it. Or make another module with make-reader, which will be required by lang and result program.

Mon, 28 Jul 2014 11:08:20 -0400 от "Alexander D. Knauth" <alexander at knauth.org>:
>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
>


-- 
Roman Klochkov


Posted on the users mailing list.