Maxim, It is possible to write a macro that "hides" local-require, although
(let () (local-require 'names) my-code ...) looks about as simple to me as (require 'names) (my-begin my-code ...) and the former does not require implementing any new unhygienic macros. The local-require macro is itself unhygienic, but at least it has already been implemented. Still, here's how you can write your macro: (require (for-syntax syntax/parse) racket/splicing) (define-syntax (my-begin stx) (syntax-parse stx [(_ body:expr ...) (with-syntax ([imports (datum->syntax stx (syntax-e (syntax 'real-names)))]) (syntax (splicing-local [(local-require imports)] body ...)))])) Here, "real-names" is the name of the module providing everything that will be bound within my-begin, and the "names" module will provide only my-begin. --Carl On Tue, Aug 23, 2011 at 3:22 AM, Maxim Romashchenko <m...@anahoret.com> wrote: > Thank you, Matthias and Carl, for a detailed reply. > > I'm now much close to my goal. Almost there. > > The approach with non-hygienic macro (item 6 in your email) works, but it > requires each symbol to be introduced explicitly (twice, with two different > names -- f and ff in your example). > > On the other hand, local-require (item 4) accomplishes almost the same thing > in a much clear way. > > (I'm not yet familiar with units, so I did not fully understand item 5, but > I assume it does essentially the same thing as local-require, but using > define-values/invoke-unit.) > > I wonder is there a way to hide require-local inside a macro, so it will be > implicit? In other words, is it possible to keep the user code as simple as > > (module uses racket > (require 'names) > (my-names-begin > (f))) > > but still to be able to access all the symbols from the module inside the > my-name-begin form, as if there is require-local call? > > Thank you. > > Best regards, Maxim. > > > On 2011-08-22 18:05, Matthias Felleisen wrote: >> >> 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