Maxim, let me re-order Carl's message. 

1. You are trying to implement a non-hygienic macro. That is, your my-begin 
macro is supposed to bind names in its expressions that are not in the scope of 
the expressions. 

2. Racket's macro system is hygienic, that is, the default does not allow such 
scope manipulations. The assumption behind this default is that such 
manipulations are usually faulty and introduce subtle (as in difficult to find) 
errors. 

3. As the word 'default' suggests, there are ways around this restriction -- 
but they tell the programmer to be careful. [[ Surprisingly, it also means that 
the seemingly-overly-restrictive hygienic macro system has more expressive 
power than the plain Lisp macro system. ]]

4. Since we don't quite understand your actual goal, Carl lists a number of 
alternatives. One is to locally require a module into a scope definition 
context: 

#lang racket/load 

(module names racket/base 
  (provide f)
  (define (f) (displayln "hello world")))

(module uses racket
  (require 'names)
  (let ()
    (local-require 'names)
    (f)))

(require 'uses)

But, as it turns out to my surprise, local-require pollutes the global scope: 

#lang racket/load 

(module names racket/base 
  (provide f)
  (define (f) (displayln "hello world")))

(module uses-bad racket
  (require 'names)
  (f)
  (let ()
    (local-require 'names)
    (f)))

(require 'uses-bad)

Perhaps I just misunderstand. 

5. An alternative is to define a unit (a first-class module), to export it and 
its signature, and to splice its definitions into a local scope, like this: 

#lang racket/load 

(module a racket
  (provide a@ a^)
  (define-signature  a^ (f))
  (define a@ (unit (import) (export a^) (define (f) (displayln "hello 
world")))))

;; testing the unit splice 
(module c racket
  (require 'a)
  (let ()
    (define-values/invoke-unit a@ (import) (export a^))
    (f)))

;; testing its locality 
(with-handlers ((exn:fail:syntax? (lambda (x)
                                    (define faulty-expressions 
(exn:fail:syntax-exprs x))
                                    (define faulty-name (map syntax-e 
faulty-expressions))
                                    (displayln `(,(exn-message x) 
,@faulty-name)))))
  (eval '(module c racket
           (require 'a)
           (let ()
             (define-values/invoke-unit a@ (import) (export a^))
             (f))
           f)))

(require 'c)

6. Last but not least, you could define an unhygienic macro like this: 

#lang racket/load 

(module names racket
  (provide (rename-out (my-begin begin)))
  
  (require (for-syntax syntax/parse))
  
  (define (f) (displayln "hello world"))
  (define-syntax (my-begin stx)
    (syntax-parse stx 
      ((_ body:expr ...)
       (let ((ff (datum->syntax stx 'f)))  ;; breaking hygiene 
         #`(let ()
             (define #,ff f)
             body
             ...))))))


(module uses racket
  (require 'names)
  (begin 
    (f)))

(require 'uses)






On Aug 22, 2011, at 10:23 AM, Carl Eastlund wrote:

> Maxim,
> 
> There are a few tools that might accomplish what you want.  To have
> scoped definitions available to a set of top-level definitions (i.e.
> those inside my-begin), use splicing-local from racket/splicing.  To
> make a set of definitions available at one place, you could package
> them up as a unit and use define-values/invoke-unit, or as a package
> and use open-package, or as a module (separate from the one with
> my-begin) and use local-require.  In all of these cases, the binding
> of those forms is unhygienic (you are binding names that are not given
> by the user of the my-begin macro), so you may have to do some direct
> manipulation of syntax objects to get the scope how you want it.  I
> hope I've at least given you some useful starting places.
> 
> Carl Eastlund
> 
> On Mon, Aug 22, 2011 at 10:04 AM, Maxim Romashchenko <m...@anahoret.com> 
> wrote:
>> Hello.
>> 
>> Thank you for your reply, Eli.
>> It looks like I need to state my question more clearly.
>> 
>> The trick I'm looking for is how to create a quasi-begin form inside which
>> you can use all the other symbols defined in the module, while those symbols
>> are not imported into top-level. In fact the only thing added to the top
>> level is supposed to be the quasi-begin form itself.
>> 
>> Best regards, Maxim.
>> 
>> 
>> On 2011-08-22 16:04, Eli Barzilay wrote:
>>> 
>>> 50 minutes ago, Maxim Romashchenko wrote:
>>>> 
>>>> --- my-module.rkt ---
>>>> #lang racket
>>>> (provide my-begin)
>>>> 
>>>> (define foo
>>>>    ...
>>>> ---------------------
>>> 
>>> You could do this:
>>> 
>>>   #lang racket
>>>   (provide (rename-out [begin my-begin]))
>>> 
>>> and get what you want,
>>> 
>>>> --- main.rkt ---
>>>> #lang racket
>>>> (require "my-module.rkt")
>>>> 
>>>> (my-begin
>>>>    (foo
>>>>      ...
>>>> -----------------
>>> 
>>> but it's probably easier to do this instead here:
>>> 
>>>   #lang racket
>>>   (require (rename-in racket [begin my-begin]))
>>> 
>> _________________________________________________
>>  For list-related administrative tasks:
>>  http://lists.racket-lang.org/listinfo/users
>> 
>> 
> 
> _________________________________________________
>  For list-related administrative tasks:
>  http://lists.racket-lang.org/listinfo/users


_________________________________________________
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/users

Reply via email to