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
_________________________________________________
For list-related administrative tasks:
http://lists.racket-lang.org/listinfo/users
_________________________________________________
For list-related administrative tasks:
http://lists.racket-lang.org/listinfo/users