* Way to control the order of macro expansion
@ 2014-01-01 22:46 Panicz Maciej Godek
2014-01-02 14:30 ` Panicz Maciej Godek
0 siblings, 1 reply; 4+ messages in thread
From: Panicz Maciej Godek @ 2014-01-01 22:46 UTC (permalink / raw)
To: guile-user@gnu.org
Hi,
is there any way to control the order of macro expansion?
Let's consider a particular problem.
I'm trying to write a macro to control the visibility
of certain definitions. I wrote it once, using define-macro,
but it seemed to loose some relevant information,
so I decided to rewrite it using define-syntax macros.
The idea is that the code
(publish
(define (f x) (+ a x))
(define (g y) (* a y))
where
(define a 5))
should expand to
(begin
(define f (and (defined? 'f) f))
(define g (and (defined? 'g) g))
(let ()
(define a 5)
(set! f (let () (define (f x) (+ a x)) f))
(set! g (let () (define (g x) (* a y)) g))))
The first thing that needs to be done is to split the
definitions between the public (before "where") and
private ones.
It can be done by introducing a helper macro
that will be called by our publish macro:
(define-syntax-rule (publish definitions ...)
(publisher (definitions ...) ()))
(define-syntax publisher
(syntax-rules (where)
((_ (where private ...) (public ...))
(private+public (private ...) (public ...)))
((_ (new defs ...) (approved ...))
(publisher (defs ...)
(approved ... new)))))
It works fine, but a simple question arises:
how to make publisher visible only within the
scope of publish macro? (I have tried many
combinations, and all of them failed, although
I don't know why)
Now, we need the definition for the private+public
syntax, that will do the actual conversion.
I believe it should look more or less like this:
(define-syntax-rule (private+public (private ...) ((df iface body ...) ...))
(letrec-syntax
((name
(syntax-rules ()
((_ (head . tail))
(name head))
((_ atom)
atom))))
(begin
(define (name iface) (and (defined? '(name iface)) iface))
...
(let ()
private ...
(set! (name iface) (let () (df iface body ...) (name iface)))
...))))
Unfortunately, there are some problems with that definition,
the most annoying being the fact that it doesn't work ;]
There are three problems, namely -- that quote, define and
set! are special forms themselves, and as such they prevent
the "name" local syntax to expand. (This can be observed
easily, because when the names "define" and "set!" and
the ' operator are replaced with some unbound identifiers,
the macro expands just as I want it to).
It seems that the expander works in the order from the
outermost to the innermost level, and from left to right.
Is there any way to force the expander to evaluate
some innermost forms first?
regards,
M.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Way to control the order of macro expansion
2014-01-01 22:46 Way to control the order of macro expansion Panicz Maciej Godek
@ 2014-01-02 14:30 ` Panicz Maciej Godek
2014-01-02 16:17 ` Chris Vine
2014-01-03 0:21 ` Panicz Maciej Godek
0 siblings, 2 replies; 4+ messages in thread
From: Panicz Maciej Godek @ 2014-01-02 14:30 UTC (permalink / raw)
To: guile-user@gnu.org
After reading some of the original paper by Dybvig[1],
I finally managed to get the macro right. The trick
was to use "with-syntax", which -- I have to admit
-- is still a little magical to me. But by mimicking
the way the procedure "generate-temporaries" has
been used in the Dybvig's implementation of letrec,
I came up with the following solution:
(define-syntax private+public
(lambda (stx)
(define (name interface)
(define (interface-name interface)
(match interface
((head . tail)
(interface-name head))
((? symbol? name)
name)))
(datum->syntax stx (interface-name (syntax->datum interface))))
(syntax-case stx ()
((_ (private ...) ((define-variant interface . body) ...))
(with-syntax (((name ...) (map name #'(interface ...))))
#`(begin
(define name (and (defined? 'name) name))
...
(let ()
private ...
(set! name
(let ()
(define-variant interface . body)
name))
...)))))))
[1] http://www.cs.indiana.edu/~dyb/pubs/tr356.pdf
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Way to control the order of macro expansion
2014-01-02 14:30 ` Panicz Maciej Godek
@ 2014-01-02 16:17 ` Chris Vine
2014-01-03 0:21 ` Panicz Maciej Godek
1 sibling, 0 replies; 4+ messages in thread
From: Chris Vine @ 2014-01-02 16:17 UTC (permalink / raw)
To: Panicz Maciej Godek; +Cc: guile-user@gnu.org
On Thu, 2 Jan 2014 15:30:32 +0100
Panicz Maciej Godek <godek.maciek@gmail.com> wrote:
> After reading some of the original paper by Dybvig[1],
> I finally managed to get the macro right. The trick
> was to use "with-syntax", which -- I have to admit
> -- is still a little magical to me. But by mimicking
> the way the procedure "generate-temporaries" has
> been used in the Dybvig's implementation of letrec,
> I came up with the following solution:
[snip]
Chapter 8 of Dybvig's "Scheme programming language, 4th edition" [1] has
a less fulsome but more exampled explanation of 'with-syntax' which
might be useful. I found it helpful recently in order to implement a
version of 'guard' which works with native guile exceptions - guile's
r6rs 'guard' does not do so[2].
Chris
[1] http://www.scheme.com/tspl4/syntax.html#./syntax:h0
[1] In doing this, I also discovered that guile's r6rs 'guard' is not
r6rs compliant, because if the exception concerned is rethrown because
there is no matching handler clause, it does so without first restoring
the dynamic context to the one in which the exception was raised.
Having said that, I prefer guile's behaviour; and you won't notice the
difference unless you have a dynamic-wind in there somewhere.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Way to control the order of macro expansion
2014-01-02 14:30 ` Panicz Maciej Godek
2014-01-02 16:17 ` Chris Vine
@ 2014-01-03 0:21 ` Panicz Maciej Godek
1 sibling, 0 replies; 4+ messages in thread
From: Panicz Maciej Godek @ 2014-01-03 0:21 UTC (permalink / raw)
To: guile-user@gnu.org
It turned out, that the above solution doesn't work
exactly as expected -- since the scopes of "private"
and "interface" get separated (by the with-syntax
form that I have been so proud of), it is impossible
for the public forms to refer to private bindings.
To solve that issue, I had to pass the private
bindings to the function passed with-syntax
and then retrieve them. For some reason (which
is unclear to me) I had to convert them to datum
and then back to syntax, because if they were
given verbatim, they failed to get renamed
properly. I'd appreciate if anyone could explain
it to me, or reviewed the code below to tell
whether the names and comments aren't
misleading (e.g. I used the name "lexical-context"
for a variable, but I'm not sure whether the entity
that it refers to can properly be called "lexical
context")
(define-syntax private+public
(lambda (stx)
(define (interface+name+body specs lexical-context)
;; the second argument is the lexical context that we
;; want to preserve while extracting the specs
(define (interface-name interface)
(match interface
((head . tail)
(interface-name head))
((? symbol? name)
name)))
`(,(datum->syntax stx (syntax->datum lexical-context))
;; for some reason we need to deconstruct and reconstruct
;; lexical-context here
,(map (lambda(spec)
(syntax-case spec ()
((interface . body)
(datum->syntax stx `(,(syntax->datum #'interface)
,(interface-name
(syntax->datum #'interface))
,(syntax->datum #'body))))))
specs)))
(syntax-case stx ()
((_ (private ...) ((pub-define . pub-spec) ...))
;; we pass the private definitions to the interface+name+body,
;; because we want to be able to refer to private definitions
;; from within the public ones (otherwise the macro processor
;; would treat them as if they were within separate contexts)
(with-syntax ((((private ...) ((interface name body) ...))
(interface+name+body #'(pub-spec ...) #'(private ...))))
#'(begin
(define name (and (defined? 'name) name))
...
(let ()
private ...
(set! name
(let ()
(pub-define interface . body)
name))
...)))))))
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2014-01-03 0:21 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-01 22:46 Way to control the order of macro expansion Panicz Maciej Godek
2014-01-02 14:30 ` Panicz Maciej Godek
2014-01-02 16:17 ` Chris Vine
2014-01-03 0:21 ` Panicz Maciej Godek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).