Help with macros writing macros in Bigloo 
Author Message
 Help with macros writing macros in Bigloo

I'm having trouble writing a macro which (among other things) writes
macros.  I'm using (or abusing) Bigloo.

Here's the idea:  I want an form like this:

(define (carry-save-adder . _bindings)
   (letsig
    ((a        (input  (3 : 0)))
     (b        (input  (3 : 0)))
     (sum      (output (3 : 0))
               (-or (-and (a gate (0 0 0 0)) (b gate (3 2 1 0)))
                    (-and (a gate (1 1 1 1)) (b gate (2 1 0 3)))
                    (-and (a gate (2 2 2 2)) (b gate (1 0 3 2)))
                    (-and (a gate (3 3 3 3)) (b gate (0 3 2 1)))))
     (carry    (output (1 : 0))
               (-or (steer '-or (1 0) (0 0 0 0) (-and (a gate (3 2 1 0))
                                                      (b gate (0 0 0 0))))
                    (steer '-or (1 0) (1 0 0 0) (-and (a gate (3 2 1 0))
                                                      (b gate (1 1 1 1))))
                    (steer '-or (1 0) (1 1 0 0) (-and (a gate (3 2 1 0))
                                                      (b gate (2 2 2 2))))
                    (steer '-or (1 0) (1 1 1 0) (-and (a gate (3 2 1 0))
                                                      (b gate (3 3 3 3)))))))
    ;; Return this signal so that the instantiation can be used in
    ;; an expression
    (sum)))

to expand into this:

(define (carry-save-adder . _bindings)
   (push-instance-path _bindings)
   (pop-instance-path
    (let        ((a        (define-signal 'a     `((3 : 0))))
                 (b        (define-signal 'b     `((3 : 0))))
                 (sum      (define-signal 'sum   `((3 : 0))))
                 (carry    (define-signal 'carry `((1 : 0)))))
       (bind-ios _bindings `((a input ,a) (b input ,b)
                             (sum output ,sum) (carry output ,carry)))
       (let-syntax ((a     (syntax-rules
                            () ((a     spec ...) (reference a     `(spec ...)))))
                    (b     (syntax-rules
                            () ((b     spec ...) (reference b     `(spec ...)))))
                    (sum   (syntax-rules
                            () ((sum   spec ...) (reference sum   `(spec ...)))))
                    (carry (syntax-rules
                            () ((carry spec ...) (reference carry `(spec ...))))))
          (assign (sum)
                  (-or (-and (a gate (0 0 0 0)) (b gate (3 2 1 0)))
                       (-and (a gate (1 1 1 1)) (b gate (2 1 0 3)))
                       (-and (a gate (2 2 2 2)) (b gate (1 0 3 2)))
                       (-and (a gate (3 3 3 3)) (b gate (0 3 2 1)))))
          (assign (carry)
                  (-or (steer '-or '(1 0) '((0 0 0 0)) (-and (a gate (3 2 1 0))
                                                             (b gate (0 0 0 0))))
                       (steer '-or '(1 0) '((1 0 0 0)) (-and (a gate (3 2 1 0))
                                                             (b gate (1 1 1 1))))
                       (steer '-or '(1 0) '((1 1 0 0)) (-and (a gate (3 2 1 0))
                                                             (b gate (2 2 2 2))))
                       (steer '-or '(1 0) '((1 1 1 0)) (-and (a gate (3 2 1 0))
                                                             (b gate (3 3 3 3))))))
          (sum)))))

By making define-signal return a (lambda (. x) (reference the-signal x)),
I can make (a `(gate (3 2 1))) work, but I'd like to get the quasiquote
implied by the use of the signal name, like (a gate (3 2 1)).

I wrote the macro as a (define-expander letsig blah), rather than as a
hygenic macro.  My expander runs properly, producing the output shown
above.  However, the (let-syntax ) hygenic macros above are not then
expanded themselves.  I tried calling (expand ...) on the expanded
form above, and that didn't get Bigloo to expand the hygenic macros
either.

If I just (eval ...) the expanded form above, the function
carry-save-adder gets generated properly.  So I'm pretty sure my
hygenic macros are okay.

I can't find any documentation with Bigloo that describes the
interaction of hygenic and (define-expander ...) macros.  Nor have I
been able to figure out how to get the latter type of macro to apply
to a reduced scope.

I'm currently considering writing my own macro expander pass that runs
over the body of the (letsig ...).  The problem with this idea is that
(a) I'll be reinventing the wheel, (b) the quoting rules for this
wheel look tough to get right, and (c) the idea of three seperate
uncooperative macro expansion passes going over my code is unpleasant.

I could use suggestions about any of the following:
  - How to write local (define-expander ...) type macros, in Bigloo.
    This would be best.
  - How to trigger hygenic macro expansion, in Bigloo.




Sun, 02 May 2004 02:26:33 GMT  
 Help with macros writing macros in Bigloo

Quote:

> I wrote the macro as a (define-expander letsig blah), rather than as a
> hygenic macro.  My expander runs properly, producing the output shown
> above.  However, the (let-syntax ) hygenic macros above are not then
> expanded themselves.  I tried calling (expand ...) on the expanded
> form above, and that didn't get Bigloo to expand the hygenic macros
> either.
> I could use suggestions about any of the following:
>   - How to write local (define-expander ...) type macros, in Bigloo.
>     This would be best.
>   - How to trigger hygenic macro expansion, in Bigloo.

It seems that the macro you want is easily expressed using standard
syntax-rules transformers, in which case I think it would be easiest
just to stick to those.  Is there some reason the following won't
suffice?:

(define-syntax letsig
  (syntax-rules ()
    ((_ arglist ((sig (type . type-specs) exp) ...) . body)
     (begin
       (push-instance-path arglist)
       (pop-instance-path
        (let ((sig (define-signal 'sig `type-specs)) ...)
          (bind-ios arglist `((sig type ,sig) ...))
          (let-syntax ((sig (syntax-rules ()
                              ((_ . specs) (reference sig `specs))))
                       ...)
            (assign (sig) exp) ...
            (let () . body))))))))

This requires that the name of the arglist be passed in.  Your version
apparently assumes the arglist is named _bindings, which seems a bit
recklessly unhygienic to me.  If you want to make it more convenient,
you could use something like this:

(define-syntax define-signal-function
  (syntax-rules ()
    ((_ name . letsig-stuff)
     (define (name . arglist) (letsig arglist . letsig-stuff)))))

And then carry-save-adder would be defined like so:

(define-signal-function carry-save-adder
    ((a        (input  (3 : 0)))
     (b        (input  (3 : 0)))
     (sum      (output (3 : 0))
               (-or (-and (a gate (0 0 0 0)) (b gate (3 2 1 0)))
                    (-and (a gate (1 1 1 1)) (b gate (2 1 0 3)))
                    (-and (a gate (2 2 2 2)) (b gate (1 0 3 2)))
                    (-and (a gate (3 3 3 3)) (b gate (0 3 2 1)))))
     (carry    (output (1 : 0))
               (-or (steer '-or (1 0) (0 0 0 0) (-and (a gate (3 2 1 0))
                                                      (b gate (0 0 0 0))))
                    (steer '-or (1 0) (1 0 0 0) (-and (a gate (3 2 1 0))
                                                      (b gate (1 1 1 1))))
                    (steer '-or (1 0) (1 1 0 0) (-and (a gate (3 2 1 0))
                                                      (b gate (2 2 2 2))))
                    (steer '-or (1 0) (1 1 1 0) (-and (a gate (3 2 1 0))
                                                      (b gate (3 3 3 3)))))))
  ;; Return this signal so that the instantiation can be used in
  ;; an expression
  (sum))

-al

Quote:
> Here's the idea:  I want an form like this:

> (define (carry-save-adder . _bindings)
>    (letsig
>     ((a        (input  (3 : 0)))
>      (b        (input  (3 : 0)))
>      (sum      (output (3 : 0))
>           (-or (-and (a gate (0 0 0 0)) (b gate (3 2 1 0)))
>                (-and (a gate (1 1 1 1)) (b gate (2 1 0 3)))
>                (-and (a gate (2 2 2 2)) (b gate (1 0 3 2)))
>                (-and (a gate (3 3 3 3)) (b gate (0 3 2 1)))))
>      (carry    (output (1 : 0))
>           (-or (steer '-or (1 0) (0 0 0 0) (-and (a gate (3 2 1 0))
>                                                  (b gate (0 0 0 0))))
>                (steer '-or (1 0) (1 0 0 0) (-and (a gate (3 2 1 0))
>                                                  (b gate (1 1 1 1))))
>                (steer '-or (1 0) (1 1 0 0) (-and (a gate (3 2 1 0))
>                                                  (b gate (2 2 2 2))))
>                (steer '-or (1 0) (1 1 1 0) (-and (a gate (3 2 1 0))
>                                                  (b gate (3 3 3 3)))))))
>     ;; Return this signal so that the instantiation can be used in
>     ;; an expression
>     (sum)))

> to expand into this:

> (define (carry-save-adder . _bindings)
>    (push-instance-path _bindings)
>    (pop-instance-path
>     (let   ((a        (define-signal 'a     `((3 : 0))))
>             (b        (define-signal 'b     `((3 : 0))))
>             (sum      (define-signal 'sum   `((3 : 0))))
>             (carry    (define-signal 'carry `((1 : 0)))))
>        (bind-ios _bindings `((a input ,a) (b input ,b)
>                         (sum output ,sum) (carry output ,carry)))
>        (let-syntax ((a     (syntax-rules
>                        () ((a     spec ...) (reference a     `(spec ...)))))
>                (b     (syntax-rules
>                        () ((b     spec ...) (reference b     `(spec ...)))))
>                (sum   (syntax-rules
>                        () ((sum   spec ...) (reference sum   `(spec ...)))))
>                (carry (syntax-rules
>                        () ((carry spec ...) (reference carry `(spec ...))))))
>      (assign (sum)
>              (-or (-and (a gate (0 0 0 0)) (b gate (3 2 1 0)))
>                   (-and (a gate (1 1 1 1)) (b gate (2 1 0 3)))
>                   (-and (a gate (2 2 2 2)) (b gate (1 0 3 2)))
>                   (-and (a gate (3 3 3 3)) (b gate (0 3 2 1)))))
>      (assign (carry)
>              (-or (steer '-or '(1 0) '((0 0 0 0)) (-and (a gate (3 2 1 0))
>                                                         (b gate (0 0 0 0))))
>                   (steer '-or '(1 0) '((1 0 0 0)) (-and (a gate (3 2 1 0))
>                                                         (b gate (1 1 1 1))))
>                   (steer '-or '(1 0) '((1 1 0 0)) (-and (a gate (3 2 1 0))
>                                                         (b gate (2 2 2 2))))
>                   (steer '-or '(1 0) '((1 1 1 0)) (-and (a gate (3 2 1 0))
>                                                         (b gate (3 3 3 3))))))
>      (sum)))))



Sun, 02 May 2004 07:05:24 GMT  
 Help with macros writing macros in Bigloo
Al,

The main idea I got from your posting was:
  Use only hygenic macros.
The implied idea was:
  If I write hygenic macros with other hygenic macros, then the
  macro system will correctly expand my newly written macros.

I've reimplemented my letsig macro as a hygenic macro, and it
works, which confirms the second idea above.  Thanks.  Now, if
you're still willing, do you want to help with my coding style?
It seems a bit bulky and inefficient right now.

Al> Is there some reason the following won't suffice?:
Al> (define-syntax letsig
Al>   (syntax-rules ()
Al>     ((_ arglist ((sig (type . type-specs) exp) ...) . body)
Al>      (begin
Al>        (push-instance-path arglist)
Al>        (pop-instance-path
Al>  (let ((sig (define-signal 'sig `type-specs)) ...)
Al>    (bind-ios arglist `((sig type ,sig) ...))
Al>    (let-syntax ((sig (syntax-rules ()
Al>                        ((_ . specs) (reference sig `specs))))
Al>                 ...)
Al>      (assign (sig) exp) ...
Al>      (let () . body))))))))

The trouble with the above is that there is some variation in
letsig.
 - Some signals are declared input or output, but some are not.
   The ones that aren't don't go into the bind-ios call.
 - Some outputs and internal signals are declared with assigned
   expressions, but some are not.  The ones that aren't don't
   generate assign statements in the body of the generated
   let-syntax.

I got it to work with these two macros:

(define-syntax letsig-aux
   (syntax-rules (input output)
      ;; Input definition
      ((_ arglist ((sig (input . shape)) . rest) (. defs)
        (. bindings) (. rules) body)
       (letsig-aux
        arglist rest
        ((sig (define-signal 'sig `shape)) . defs)
        ((sig input ,sig) . bindings)
        ((sig (syntax-rules () ((_ . specs) (reference sig `specs)))) . rules)
        body))
      ;; Output definition
      ((_ arglist ((sig (output . shape)) . rest) (. defs)
        (. bindings) (. rules) body)
       (letsig-aux
        arglist rest
        ((sig (define-signal 'sig `shape)) . defs)
        ((sig output ,sig) . bindings)
        ((sig (syntax-rules () ((_ . specs) (reference sig `specs)))) . rules)
        body))
      ;; Output definition with assignment
      ((_ arglist ((sig (output . shape) expr) . rest) (. defs)
        (. bindings) (. rules) (. body))
       (letsig-aux
        arglist rest
        ((sig (define-signal 'sig `shape)) . defs)
        ((sig output ,sig) . bindings)
        ((sig (syntax-rules () ((_ . specs) (reference sig `specs)))) . rules)
        ((assign (sig) expr) . body)))
      ;; Internal definition
      ((_ arglist ((sig (. shape)) . rest) (. defs)
        bindings (. rules) body)
       (letsig-aux
        arglist rest
        ((sig (define-signal 'sig `shape)) . defs)
        bindings
        ((sig (syntax-rules () ((_ . specs) (reference sig `specs)))) . rules)
        body))
      ;; Internal definition with assignment
      ((_ arglist ((sig (. shape) expr) . rest) (. defs)
        bindings (. rules) (. body))
       (letsig-aux
        arglist rest
        ((sig (define-signal 'sig `shape)) . defs)
        bindings
        ((sig (syntax-rules () ((_ . specs) (reference sig `specs)))) . rules)
        ((assign (sig) expr) . body)))
      ;; Final assembly
      ((_ arglist () defs bindings rules (. body))
       (begin
          (push-instance-path arglist)
          (pop-instance-path
           (let defs
                 (bind-ios arglist `bindings)
              (let-syntax rules
                    . body)))))))

(define-syntax letsig
   (syntax-rules ()
      ((_ arglist signals . body)
       (letsig-aux arglist signals () () () body))))

I dislike my solution for two reasons:
 - It reverses the order of the arguments to bind-ios.  The easy
   workaround is to put a (reverse ...) in that routine, but still...
 - It's big and it iterates.

Is there some better way to represent variant iterated patterns in
a hygenic macro?




Tue, 04 May 2004 01:39:04 GMT  
 Help with macros writing macros in Bigloo

Quote:

> The main idea I got from your posting was:
>   Use only hygenic macros.

One idea I meant to impart was "Don't use unhygienic macros without
good reason".  One source of confusion here is that people sometimes
use "hygienic macros" as a synonym for "syntax-rules macros".  Macro
hygiene is actually a stand-alone concept, and any macro system will
allow you to write hygienic macros if you are careful.  A feature of
syntax-rules is that it does automatic renaming, making hygiene easy.
A limitation of syntax-rules is that it cannot be used to write
unhygienic macros.

Another source of confusion is that people sometimes say "hygiene"
when they mean "referential transparency".  That's the mistake I made
in my last post.  The two concepts are defined in r5rs and together
constitute lexical scope for macros.  Your original letsig macro
assumed that there was a variable named _bindings in the scope of the
macro call, and inserted a reference to it.  This is impossible to do
with syntax-rules macros, and generally not a good idea anyway.  It is
clearer to pass the name of the variable to the macro.

Quote:
> The implied idea was:
>   If I write hygenic macros with other hygenic macros, then the
>   macro system will correctly expand my newly written macros.

> I've reimplemented my letsig macro as a hygenic macro, and it
> works, which confirms the second idea above.  Thanks.  Now, if
> you're still willing, do you want to help with my coding style?
> It seems a bit bulky and inefficient right now.
> Is there some better way to represent variant iterated patterns in
> a hygenic macro?

First, you should consider whether the convenience of the variants is
worth the inconsistency.  Newcomers to lisp (no, I don't mean you,
this is an example) always think its outrageous to have to say (+ 3 (/
1 2)) rather than 3+1/2, because it takes some time to realize the
benefits of a regular syntax.  Accordingly, one should give some
scrutiny to a variant form of a macro call before deciding whether it
is justified.

One example of a possible way to respecify letsig so that it is more
regular (and consequently easier to implement) is to require all the
signals to be grouped by type (input/output/internal).  Another idea
would be to have internal signals specified as (internal . shape), for
consistency with (input . shape) and (output . shape).  Or perhaps
just add a level of parentheses, so that you have (input shape),
(output shape), and (shape), which would at least remove the ambiguity
between whether something is the first element of the shape or is the
type of the signal.  Cf. the standard specification for let, which is
an excellent example of what not to do (the named variant should be a
separate macro).

I have no idea what your requirements are, and I'm not saying that
your current spec for letsig is too hairy.  I'm just urging regularity
in general, and trying to show what sorts of changes should be
considered for achieving it.

All that being said, here's how I would write the macro to get the
semantics you currently desire:

(define-syntax apply-rules
  (syntax-rules ()
    ((_ args literals . rules)
     (let-syntax ((x (syntax-rules literals . rules))) (x . args)))))

(define-syntax letsig
  (syntax-rules ()
    ((_ arglist ((sig type . opt-exp) ...) . body)
     (begin
       (push-instance-path arglist)
       (pop-instance-path
        (let ((sig (define-signal 'sig (apply-rules type (input output)
                                         ((_ input  . shape) `shape)
                                         ((_ output . shape) `shape)
                                         ((_        . shape) `shape))))
              ...)
          (bind-ios arglist

                          ((_ input  . shape) `((sig input  ,sig)))
                          ((_ output . shape) `((sig output ,sig)))
                          ((_        . shape) '()))
                      ...))
          (let-syntax ((sig (syntax-rules ()
                              ((_ . specs) (reference sig `specs))))
                       ...)
            (apply-rules opt-exp () ((_) #f) ((_ exp) (assign (sig) exp)))
            ...
            (let () . body))))))))

-al



Tue, 04 May 2004 07:39:02 GMT  
 Help with macros writing macros in Bigloo

Quote:


>>The main idea I got from your posting was:
>>  Use only hygenic macros.

> One idea I meant to impart was "Don't use unhygienic macros without
> good reason".  One source of confusion here is that people sometimes
> use "hygienic macros" as a synonym for "syntax-rules macros".  Macro
> hygiene is actually a stand-alone concept, and any macro system will
> allow you to write hygienic macros if you are careful.

This is false unless you restrict yourself to a certain small class of
macros -- those that do not insert free occurences of some globally
bound identifier into their expansion.  To avoid inadvertent name
capture in the case of free identifiers that occur in the macro's output,
the macro system must perform renaming of identifiers in "the rest
of the program", not just in the output of the macro itself. Not every
macro system does that.

Quote:
> A feature of
> syntax-rules is that it does automatic renaming, making hygiene easy.
> A limitation of syntax-rules is that it cannot be used to write
> unhygienic macros.

It is fairly easy to extend syntax-rules in such a way that hygiene
can be circumvented where this is desired.  The other way around (writing
hygienic macros in a non-hygienic macro system) is not easy at all.
In fact, I'd say that in the general case it is impossible.

--
-Matthias



Wed, 05 May 2004 00:20:10 GMT  
 Help with macros writing macros in Bigloo

Quote:

> [...] To avoid inadvertent name
> capture in the case of free identifiers that occur in the macro's output,
> the macro system must perform renaming of identifiers in "the rest
> of the program", not just in the output of the macro itself. Not every
> macro system does that.

This "renaming of identifiers" is just the way we're supposed to
understand it, right?

Chez Scheme has a "gensym" function that, if I understand correctly,
produces a unique symbol that can't clash with any past or future
symbol. The name might clash, but internally, they're guaranteed to be
unique. I borrowed the idea for my own C++ implementation of symbols.
The idea behind my symbol class is that it keeps a pair of dictionaries
of associations between names and integers. The symbols get created via
strings, but passed around, stored, and compared as integers.

The trick with gensym is simply to add an entry to the number-keyed
dictionary without adding a corresponding entry to the string-keyed
dictionary.

Anyway, this would seem to be a particularly easy way to guarantee
hygenic macro symbols.

-thant



Wed, 05 May 2004 01:29:01 GMT  
 Help with macros writing macros in Bigloo

Quote:


>> [...] To avoid inadvertent name
>> capture in the case of free identifiers that occur in the macro's output,
>> the macro system must perform renaming of identifiers in "the rest
>> of the program", not just in the output of the macro itself. Not every
>> macro system does that.

> This "renaming of identifiers" is just the way we're supposed to
> understand it, right?

> Chez Scheme has a "gensym" function that, if I understand correctly,
> produces a unique symbol that can't clash with any past or future
> symbol. The name might clash, but internally, they're guaranteed to be
> unique. I borrowed the idea for my own C++ implementation of symbols.
> The idea behind my symbol class is that it keeps a pair of dictionaries
> of associations between names and integers. The symbols get created via
> strings, but passed around, stored, and compared as integers.

> The trick with gensym is simply to add an entry to the number-keyed
> dictionary without adding a corresponding entry to the string-keyed
> dictionary.

> Anyway, this would seem to be a particularly easy way to guarantee
> hygenic macro symbols.

But it is not enough!  What you get from gensym (which, indeed, for this

purpose must return a symbol that cannot clash with any other symbol)
is just the easy part: Avoiding name capture due to binders introduced
into the macro output.

The generic example is the "swap" macro, e.g.,

   (define-syntax swap
      (syntax-rules ()
        ((_ x y) (let ((tmp x)) (set! x y) (set! y tmp)))))

For this to work, "tmp" must be a gensym-ed name, otherwise one gets
breakage in code like this:

    (let ((tmp (get-temperature-reading)))
      ...
      (swap tmp foo)
      ...)

Gensym-ing "tmp" can, obviously, be done entirely within the expansion of
the swap macro itself.

However, there is the other case of name capture which happens when you
do this:

(define (error msg) (display msg) (newline) (exit 17))

(define-syntax assert
    (syntax-rules ()
       ((_ condition) (if condition '()
                          (error `(Assertion failed: ,condition))))))

This will break when you do something like:

   (let ((error (get-last-error-code)))
      (assert (not (equal error '())))
      ...)

The problem is that there is a local binding of "error" that shadows the
binding that the output of the assert macro is supposed to refer to.
In fact, the output here would have two instances of "error" -- with two
different intended meanings.

A hygienic macro system solves this problem by effectively renaming the
let-binding of "error" that shadows the original one.  Along with this
renaming, of course, it must also rename the corresponding uses of "error" --
but not the other uses of "error" such as the one that appears in the
definition of "assert". Notice that the binding to be renamed is outside
any macro invocation.

Obviously, a simple gensym approach just does not cut it -- no matter how
fancy you make your gensym.

--
-Matthias



Wed, 05 May 2004 03:20:44 GMT  
 Help with macros writing macros in Bigloo

[...]

Quote:
> The problem is that there is a local binding of "error" that shadows the
> binding that the output of the assert macro is supposed to refer to.

[...]

Ah...thanks. I would have thought of the 'error' in the macro to be
bound to the version defined at the time the macro itself was defined,
but I keep forgetting Scheme doesn't work that way. (Or macros don't
work that way. I have to think about it to decide which.)

-thant



Wed, 05 May 2004 05:26:56 GMT  
 Help with macros writing macros in Bigloo

Quote:


> > One idea I meant to impart was "Don't use unhygienic macros without
> > good reason".  One source of confusion here is that people sometimes
> > use "hygienic macros" as a synonym for "syntax-rules macros".  Macro
> > hygiene is actually a stand-alone concept, and any macro system will
> > allow you to write hygienic macros if you are careful.

> This is false unless you restrict yourself to a certain small class of
> macros -- those that do not insert free occurences of some globally
> bound identifier into their expansion.

You are referring apparently to referential transparency.  As I said
in the next paragraph:

Quote:
> Another source of confusion is that people sometimes say "hygiene"
> when they mean "referential transparency".  That's the mistake I made
> in my last post.  The two concepts are defined in r5rs and together
> constitute lexical scope for macros.

It seems we both have a tendency to think of these as two parts of a
single concept named "hygiene", but I think it's better to use the
r5rs terminology in which the term for the overall concept is "lexical
scope".  I realize the nomenclature is not universally established,
and I should have just quoted the definitions I was using.  From r5rs
4.3:

  The syntactic keyword of a macro may shadow variable bindings, and
  local variable bindings may shadow keyword bindings.  All macros
  defined using the pattern language are "hygienic" and "referentially
  transparent" and thus preserve Scheme's lexical scoping:

     * If a macro transformer inserts a binding for an identifier
       (variable or keyword), the identifier will in effect be renamed
       throughout its scope to avoid conflicts with other identifiers.
       Note that a define at top level may or may not introduce a
       binding; see section 5.2.

     * If a macro transformer inserts a free reference to an identifier,
       the reference refers to the binding that was visible where the
       transformer was specified, regardless of any local bindings that
       may surround the use of the macro.

Quote:
> To avoid inadvertent name capture in the case of free identifiers
> that occur in the macro's output, the macro system must perform
> renaming of identifiers in "the rest of the program", not just in
> the output of the macro itself. Not every macro system does that.

Right, but any old quasiquote/gensym macro system will enable you to
insert bound variables that will not conflict with other identifiers.

Quote:
> It is fairly easy to extend syntax-rules in such a way that hygiene
> can be circumvented where this is desired.

Are you familiar with any implementations of this?  I've been thinking
about various possible extensions to syntax-rules, with the idea of
possibly writing a srfi.  I am interested in seeing any examples of
ways in which other people have fit extra functionality into the
syntax of syntax-rules.  The extensions of which I'm aware are:
ellipsis quotation, mixed-rank templates, consecutive ellipsis
templates like (x ... ...), and pattern ellipses in the middle of a
list or vector.

-al



Wed, 05 May 2004 07:08:08 GMT  
 Help with macros writing macros in Bigloo

Quote:


> [...]

>> The problem is that there is a local binding of "error" that shadows the
>> binding that the output of the assert macro is supposed to refer to.

> [...]

> Ah...thanks. I would have thought of the 'error' in the macro to be
> bound to the version defined at the time the macro itself was defined,
> but I keep forgetting Scheme doesn't work that way. (Or macros don't
> work that way. I have to think about it to decide which.)

No, this *is* the way it is supposed to work -- except that naive (i.e.,
non-hygienic) macro systems can't do it.  Not even with a fancy gensym.

Matthias



Wed, 05 May 2004 11:19:52 GMT  
 Help with macros writing macros in Bigloo

[...]

Quote:
> No, this *is* the way it is supposed to work -- except that naive (i.e.,
> non-hygienic) macro systems can't do it.  Not even with a fancy gensym.

I understand which value is supposed to be bound to 'error'. What I'm
talking about is when. The problem of hygenic macros would seem to me to
be much easier to solve if the occurrence of 'error' in the macro was
bound at the time the macro was defined instead of at the time the
result of the macro transformation was evaluated. But this clashes with
the ability in Scheme to refer to variables that have yet to be defined.

I've (obviously) never implemented Scheme, but I'm playing with some
ideas and I want to understand this.

-thant



Wed, 05 May 2004 22:05:03 GMT  
 Help with macros writing macros in Bigloo
Hi

    For an interpreter, an expression is processed
in three steps (at least in my implementation)

    (1) expansion (rewrites and macro application)
    (2) bytecode "compilation" + optimization
    (3) evaluation.

    In your case, the variable "error" in the
let-expression, is renamed at the time of
expansion.  The actual binding of
the variable "error" occurs later, at the time of
evaluation.

=============================

    As I noted above, every expression is
rewritten by an expander.  That itself is a two-step
process:  (1) if an expression
is a use of macro, the expander will apply the
macro to the expression  (2) it will then rewrite
the resulting expression, so as to rename all local
variables.  For expressions that contain sub-expressions,
(1) and (2) are alternatiingly applied as one
descends into the innermost expression.
If one has an expression that is not a use of macro,
the expander will still apply only step (2); that is,
it will simply rewrite it.

    So, if you have

    (let ((error ...)) ...)

since the above expression is not a use of macro,
it will be rewritten, renaming the local variable "error."



Wed, 05 May 2004 23:13:24 GMT  
 Help with macros writing macros in Bigloo

Quote:

> I've been thinking
> about various possible extensions to syntax-rules, with the idea of
> possibly writing a srfi.  I am interested in seeing any examples of
> ways in which other people have fit extra functionality into the
> syntax of syntax-rules.  The extensions of which I'm aware are:
> ellipsis quotation, mixed-rank templates, consecutive ellipsis
> templates like (x ... ...), and pattern ellipses in the middle of a
> list or vector.

You should definitely check out Christian Quenniec's work (I may have
misspelled his name, unfortunately) in "Lisp In Small Pieces".  If you
speak French more fluently than English, the original French-language
edition is entitled "Les Langages Lisp."  

Anyway, he outlines a very elegant macro system wherein the macro
syntax is considered as a way of defining a function in a "macro-
expansion program" which has its own namespace, runtime, etc.
Basically it makes the macro-expander into just another scheme
program.  When he needs to define a macro that involves more than
a simple transformation-in-place (for a class system) he defines
a macro in the language used by the macro-expansion program itself,
a "meta-macro" that injects all the needed definitions for his class
system.  The clear implication is that if you happen to need macros
of higher level yet, or if you have to execute a whole bunch of scheme
code to figure out what your macro should inject, all you have to do
is define additional functions in the reading/macro-expanding program.

                                Bear



Fri, 07 May 2004 03:35:39 GMT  
 Help with macros writing macros in Bigloo

Quote:

>     For an interpreter, an expression is processed
> in three steps (at least in my implementation)

[...]

Thanks. That fills in a gap in my understanding.

-thant



Fri, 07 May 2004 22:43:33 GMT  
 Help with macros writing macros in Bigloo
Al> First, you should consider whether the convenience of the variants is
AL> worth the inconsistency.

I am a newcomer to lisp and scheme.  This is the first thing I've written
in either language.  I've already written this netlisting system once in
Perl, then again in C++/perl/lex, and run into some limitations each time.
This is my third implementation.  For this implementation, I'm attempting
to make it possible to add to the netlisting language with self-contained
modules.  This is tricky and requires a lot of cooperation from the
netlister -- it's a little like trying to add things like a partial
redundancy elimination pass to a scheme compiler from within the scheme
code being compiled.

So far, it appears the cost of the inconsistency of the letsig form is
some extra code in the macro system.  That's fine.  If I find that the
inconsistent form gets in the way of modular extensions, I'll axe it.

Al> All that being said, here's how I would write the macro to get the
Al> semantics you currently desire:

Very neat.  Thank you.

Being a hardware type, I tend to worry about the execution speed of these
macro expansions.  It's an old habit.  Does anyone know what sorts of
constructions tend to slow down macro expansion systems?




Sat, 08 May 2004 10:40:32 GMT  
 
 [ 17 post ]  Go to page: [1] [2]

 Relevant Pages 

1. A macro involving two sub-macros - where the 2nd macro needs results from the first

2. help sought for macro defining macro

3. Macros in Bigloo (1.7) ?

4. Bigloo & macros

5. Need help with macro writing

6. macro -vs- macro/codeblock

7. syntax-rules macros with sub-macros

8. Scheme macro source: rewriter-widget, a widely applicable macro interface

9. Macros defining macros with define-syntax

10. symbol-macros and regular macros

11. Question about a macro-defining macro

12. Macro-Defining Macros

 

 
Powered by phpBB® Forum Software