Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Idiot's guide to Scheme macros?
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  Messages 1 - 25 of 37 - Collapse all  -  Translate all to Translated (View all originals)   Newer >
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Tim Bradshaw  
View profile  
 More options Mar 15 2011, 2:03 pm
Newsgroups: comp.lang.scheme
From: Tim Bradshaw <t...@tfeb.org>
Date: Tue, 15 Mar 2011 18:03:23 +0000
Local: Tues, Mar 15 2011 2:03 pm
Subject: Idiot's guide to Scheme macros?
Hi, does anyone know of a guide to Scheme macros (specifically to
Racket's: I am not sure how standardised macros are now, though I know
they used not to be) for someone very familiar with CL macros?  I don't
have a problem with the notion of what a macro is, for instance, and I
can write simple things based on the Racket "guide" material, but the
reference material is less approachable (as, obviously, it's reference
material...).

Thanks

--tim


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Aaron W. Hsu  
View profile  
 More options Mar 15 2011, 8:23 pm
Newsgroups: comp.lang.scheme
From: "Aaron W. Hsu" <arcf...@sacrideo.us>
Date: Tue, 15 Mar 2011 20:23:57 -0400
Local: Tues, Mar 15 2011 8:23 pm
Subject: Re: Idiot's guide to Scheme macros?

On Tue, 15 Mar 2011 14:03:23 -0400, Tim Bradshaw <t...@tfeb.org> wrote:
> Hi, does anyone know of a guide to Scheme macros (specifically to  
> Racket's: I am not sure how standardised macros are now, though I know  
> they used not to be) for someone very familiar with CL macros?  I don't  
> have a problem with the notion of what a macro is, for instance, and I  
> can write simple things based on the Racket "guide" material, but the  
> reference material is less approachable (as, obviously, it's reference  
> material...).

Various people have attempted to write something like this, and while  
there have been various attempts, nothing I have seen adequately prepares  
someone for writing hygienic and hygiene-bending macros in syntax-case (or  
really, any other system for that matter). Doing so is different than  
writing CL macros, and I would argue, generally more pleasant.

I would recommend the main papers on syntax-case and its workings as a  
good supplement to the guides, and you can also check out TSPL4 [1] as an  
additional reference to the syntax-case system, variations (minor, ish) of  
which are in all R6RS capable Schemes (Racket included).

        Aaron W. Hsu

[1] http://www.scheme.com/tspl4/

--
Programming is just another word for the lost art of thinking.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
WJ  
View profile  
 More options Mar 15 2011, 8:08 pm
Newsgroups: comp.lang.scheme
From: "WJ" <w_a_x_...@yahoo.com>
Date: 16 Mar 2011 00:08:47 GMT
Local: Tues, Mar 15 2011 8:08 pm
Subject: Re: Idiot's guide to Scheme macros?

Tim Bradshaw wrote:
> Hi, does anyone know of a guide to Scheme macros (specifically to Racket's:
> I am not sure how standardised macros are now, though I know they used not
> to be) for someone very familiar with CL macros?  I don't have a problem
> with the notion of what a macro is, for instance, and I can write simple
> things based on the Racket "guide" material, but the reference material is
> less approachable (as, obviously, it's reference material...).

> Thanks

> --tim

Both Guile Scheme and Bigloo Scheme support define-macro;
I presume that other Schemes do also.

(define-macro (inc! x . delta)
  (if (null? delta)
    `(set! ,x (1+ ,x))
    `(set! ,x (+ ,x ,@delta))))


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Aaron W. Hsu  
View profile  
 More options Mar 15 2011, 10:57 pm
Newsgroups: comp.lang.scheme
From: "Aaron W. Hsu" <arcf...@sacrideo.us>
Date: Tue, 15 Mar 2011 22:57:56 -0400
Local: Tues, Mar 15 2011 10:57 pm
Subject: Re: Idiot's guide to Scheme macros?

On Tue, 15 Mar 2011 20:08:47 -0400, WJ <w_a_x_...@yahoo.com> wrote:
> Both Guile Scheme and Bigloo Scheme support define-macro;
> I presume that other Schemes do also.

Indeed, any Scheme that supports syntax-case can have a form of defmacro.  
However, one should not program using defmacro in Scheme. Doing so is  
about as close to intentionally introducing bugs into your programs as I  
can think of at the moment.

        Aaron W. Hsu

--
Programming is just another word for the lost art of thinking.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Bakul Shah  
View profile  
 More options Mar 16 2011, 2:56 am
Newsgroups: comp.lang.scheme
From: Bakul Shah <use...@bitblocks.com>
Date: Tue, 15 Mar 2011 23:56:40 -0700
Local: Wed, Mar 16 2011 2:56 am
Subject: Re: Idiot's guide to Scheme macros?
On 3/15/11 11:03 AM, Tim Bradshaw wrote:

> Hi, does anyone know of a guide to Scheme macros (specifically to Racket's: I am not sure how
> standardised macros are now, though I know they used not to be) for someone very familiar with CL
> macros? I don't have a problem with the notion of what a macro is, for instance, and I can write
> simple things based on the Racket "guide" material, but the reference material is less approachable
> (as, obviously, it's reference material...).

I found R5RS pretty easy to follow. See section 7.3 for some examples.
Also see section 12 in R6RS library.

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Marco Maggi  
View profile  
 More options Mar 16 2011, 3:16 am
Newsgroups: comp.lang.scheme
From: Marco Maggi <ma...@maggi.invalid>
Date: Wed, 16 Mar 2011 08:16:08 +0100
Local: Wed, Mar 16 2011 3:16 am
Subject: Re: Idiot's guide to Scheme macros?

Tim Bradshaw wrote:
> Hi,  does  anyone  know   of  a  guide  to  Scheme  macros
> (specifically to Racket's: I  am not sure how standardised
> macros are  now, though  I know they  used not to  be) for
> someone very familiar with CL macros?

Racket's macro facilities are the most powerful and also the
most complex  among Scheme implementations, as far  as I can
tell.  I suggest you to take this approach:

1. Learn syntax-rules.
2. Learn the syntax-case library.
3. Learn Rackets macro system.

  For syntax-rules: I suggest you to search for "syntax-rule
tutorial" and  pick any of the short  introductions you find
this  way,  just  to  get  you  started;  then  read  "JRM's
Syntax-rules Primer  for the Merely  Eccentric"[1], which is
long and should satisfy your needs.

  For   syntax-case:  I   have   found  neither   satisfying
documentation, nor tutorials,  for learning it without pain;
this  includes  my own  introduction  to  the R6RS  relevant
chapter[2].   I think  that  both the  chapter  in the  R6RS
document  and   the  chapter  in   "The  Scheme  Programming
Language"[3] are  for people who "already get  it", the same
goes for all  the papers I have seen  so far: people writing
those  have  long  forgotten  what  does it  mean  to  be  a
beginner.   Also, to learn  syntax-case one  has to  build a
mental  model of  how the  macro expander  works, and  it is
totally opaque at  first.  The only way is  to have patience
with yourself and try to read everything you stumble upon.

  I  have not  learned Racket  macros, so  I  cannot suggest
anything; when  I tried to read  their documentation without
knowing syntax-case first,  I understood almost nothing; now
that I know a bit  of syntax-case I can understand something
more of  what I  remember; so I  guess that,  after learning
syntax-case,  you  will  be  able  to  use  their  reference
material with some success.

HTH

[1] <http://eval.apply.googlepages.com/eccentric.txt>
[2] <http://marcomaggi.github.com/docs/nausicaa.html/stdlib-syntax_002dcas...>
[3] <http://www.scheme.com/tspl4/syntax.html#./syntax:h0>
--
Marco Maggi


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Tim Bradshaw  
View profile  
 More options Mar 16 2011, 4:23 am
Newsgroups: comp.lang.scheme
From: Tim Bradshaw <t...@tfeb.org>
Date: Wed, 16 Mar 2011 08:23:15 +0000
Local: Wed, Mar 16 2011 4:23 am
Subject: Re: Idiot's guide to Scheme macros?
On 2011-03-16 00:23:57 +0000, Aaron W. Hsu said:

> Various people have attempted to write something like this, and while
> there have been various attempts, nothing I have seen adequately
> prepares someone for writing hygienic and hygiene-bending macros in
> syntax-case (or really, any other system for that matter). Doing so is
> different than writing CL macros, and I would argue, generally more
> pleasant.

Thanks, and thanks to the other responses.

One thing I probably should have made more clear is that I'm at the
point where I can pretty easily write things with syntax-rules but
there are things I want to do which I think it is preventing me from
doing (as it should) so I think I need to understand syntax-case &
friends more thoroughly.

The "things I want to do" are essentially introduce bindings which the
user of the macro can see (which I think is the same thing as "not be
hygenic"), so I want something like this to "work":

(define-syntax bodging
  (syntax-rules ()
    ((bodging form ...)
     (let ((x 1)) form ...))))

(bodging x)

I do understand why syntax-rules is making it not "work", and I'm glad
it does so in general.

I'm aware that there are things out there which essentially look like
the CL macro system, but I don't want to use them as I already
understand that (though, if they can be implemented in terms of
syntax-case &c it might well be interesting to look at their
implementation to see how they do it).

--tim


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Pascal J. Bourguignon  
View profile  
 More options Mar 16 2011, 5:25 am
Newsgroups: comp.lang.scheme
From: "Pascal J. Bourguignon" <p...@informatimago.com>
Date: Wed, 16 Mar 2011 10:25:26 +0100
Local: Wed, Mar 16 2011 5:25 am
Subject: Re: Idiot's guide to Scheme macros?

Tim Bradshaw <t...@tfeb.org> writes:
> I'm aware that there are things out there which essentially look like
> the CL macro system, but I don't want to use them as I already
> understand that ...

I don't think that's a valid reason not to use them, on the contrary.

In addition to already understanding them, they would have the advantage
of letting you write code more easily transposable to Common Lisp.

--
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Tim Bradshaw  
View profile  
 More options Mar 16 2011, 5:54 am
Newsgroups: comp.lang.scheme
From: Tim Bradshaw <t...@tfeb.org>
Date: Wed, 16 Mar 2011 09:54:03 +0000
Local: Wed, Mar 16 2011 5:54 am
Subject: Re: Idiot's guide to Scheme macros?
On 2011-03-16 09:25:26 +0000, Pascal J. Bourguignon said:

> I don't think that's a valid reason not to use them, on the contrary.

Since my purpose is to learn the Scheme (specifically Racket) macro
system, I rather think it is.

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Marco Maggi  
View profile  
 More options Mar 16 2011, 11:49 am
Newsgroups: comp.lang.scheme
From: Marco Maggi <ma...@maggi.invalid>
Date: Wed, 16 Mar 2011 16:49:17 +0100
Local: Wed, Mar 16 2011 11:49 am
Subject: Re: Idiot's guide to Scheme macros?

Tim Bradshaw wrote:
> (define-syntax bodging
>  (syntax-rules ()
>    ((bodging form ...)
>     (let ((x 1)) form ...))))
> (bodging x)
> I do understand why  syntax-rules is making it not "work",
> and I'm glad it does so in general.

Good.  So you can understand why the following works:

(define-syntax bodging
  (syntax-rules ()
    ((bodging var form ...)
     (let ((var 1)) form ...))))

(bodging x x)

by expanding to:

(let ((x 1)) x)
;;     ^     ^
;;     |     |
;;     |      -- reference position
;;      -- binding position

To be able to write:

(bodging x)

and  achieve the  same result,  we  want to  generate the  X
identifier in the  binding position as if it  was present in
the input form; here:

(define-syntax bodging
  (lambda (macro-use-syntax-object-holding-input-form)
    (syntax-case macro-use-syntax-object-holding-input-form ()
      ((bodging form ...)
       (let ((the-dirty-identifier (datum->syntax (syntax bodging) 'x)))
         (quasisyntax
          (let (((unsyntax the-dirty-identifier) 1))
            form ...)))))))

or more briefly but completely equivalent:

(define-syntax bodging
  (lambda (stx)
    (syntax-case stx ()
      ((bodging form ...)
       #`(let ((#,(datum->syntax #'bodging 'x) 1))
           form ...)))))

notice how  QUASISYNTAX, UNSYNTAX and SYNTAX  are similar to
QUASIQUOTE, UNQUOTE and QUOTE and the abbreviations:

#` #, #'

are similar to the abbreviations:

` , '

HTH
--
Marco Maggi


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Bakul Shah  
View profile  
 More options Mar 16 2011, 1:45 pm
Newsgroups: comp.lang.scheme
From: Bakul Shah <use...@bitblocks.com>
Date: Wed, 16 Mar 2011 10:45:41 -0700
Local: Wed, Mar 16 2011 1:45 pm
Subject: Re: Idiot's guide to Scheme macros?
On 3/16/11 1:23 AM, Tim Bradshaw wrote:

> The "things I want to do" are essentially introduce bindings which the user of the macro can see
> (which I think is the same thing as "not be hygenic"), so I want something like this to "work":

> (define-syntax bodging
> (syntax-rules ()
> ((bodging form ...)
> (let ((x 1)) form ...))))

> (bodging x)

> I do understand why syntax-rules is making it not "work", and I'm glad it does so in general.

May be this will help? http://blog.scheme.dk/2006/05/how-to-write-unhygienic-macro.html

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Tim Bradshaw  
View profile  
 More options Mar 16 2011, 1:49 pm
Newsgroups: comp.lang.scheme
From: Tim Bradshaw <t...@tfeb.org>
Date: Wed, 16 Mar 2011 17:49:05 +0000
Local: Wed, Mar 16 2011 1:49 pm
Subject: Re: Idiot's guide to Scheme macros?
On 2011-03-16 15:49:17 +0000, Marco Maggi said:

> Good.  So you can understand why the following works:

> (define-syntax bodging
>   (syntax-rules ()
>     ((bodging var form ...)
>      (let ((var 1)) form ...))))

> (bodging x x)

Yes, that was as far as I had got (and actually, that's almost
certainly stylistically preferable to what I'm aiming at, but as I said
what I'm trying to do is understand the guts of the macro system, not
write pretty macros...).

I will study the rest of your article: thank you!


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Aaron W. Hsu  
View profile  
 More options Mar 16 2011, 5:04 pm
Newsgroups: comp.lang.scheme
From: "Aaron W. Hsu" <arcf...@sacrideo.us>
Date: Wed, 16 Mar 2011 17:04:20 -0400
Local: Wed, Mar 16 2011 5:04 pm
Subject: Re: Idiot's guide to Scheme macros?
On Wed, 16 Mar 2011 03:16:08 -0400, Marco Maggi <ma...@maggi.invalid>  
wrote:

> Racket's macro facilities are the most powerful and also the
> most complex  among Scheme implementations, as far  as I can
> tell.

Among Schemes, I believe that Chez Scheme and Racket hold the ``honors''  
of most powerful and subsequently most involved macro systems. Power,  
though, makes for interesting debates, so I am hesitant to make absolute  
claims about power when it comes to syntax-case. Racket is less forgiving  
in certain areas related to macro systems (though not its macro system  
proper) than Chez is, including libraries and phasing. However, both have  
powerful extensions to the R6RS syntax-case that go beyond what I believe  
any other syntax-case based implementation does.

        Aaron W. Hsu

--
Programming is just another word for the lost art of thinking.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Aaron W. Hsu  
View profile  
 More options Mar 16 2011, 5:17 pm
Newsgroups: comp.lang.scheme
From: "Aaron W. Hsu" <arcf...@sacrideo.us>
Date: Wed, 16 Mar 2011 17:17:55 -0400
Local: Wed, Mar 16 2011 5:17 pm
Subject: Re: Idiot's guide to Scheme macros?
On Wed, 16 Mar 2011 11:49:17 -0400, Marco Maggi <ma...@maggi.invalid>  
wrote:

There are some stylistic things one might want to try if you want to see  
different ways of doing this:

(define-syntax (bodging x)
   (syntax-case x ()
     [(k form ...)
      (with-implicit (k x)
        #'(let ([x 1]) form ...))]))

(define-syntax (bodging x)
   (syntax-case x ()
     [(k form ...)
      (with-syntax ([x (datum->syntax #'k 'x)])
        #'(let ([x 1]) form ...))]))

I am not sure how many of these forms and extensions Racket has, but they  
are trivial to provide and writing those might be an interesting exercise.  
The with-implicit form [1] makes it cleaner to do these sorts of things,  
and the with-syntax form allows a cleaner final syntax, so that you do not  
need to use quasisyntax and quasiunquote.

Just to give you some variety to practice your macros on.

If you really want to play around with how hygiene works, there is an  
interesting example in CSUG8 that shows how one might implement a module  
system with interfaces and implementation separately by writing macros  
around a combined module form `module'. [2] It's a good exercise, and you  
can write a naive `module' form for Racket as well to try these things  
out. There are some gotchas to watch out for as well. [3]

        Aaron W. Hsu

[1] http://www.scheme.com/csug8/syntax.html#./syntax:s11
[2] http://www.scheme.com/csug8/syntax.html#./syntax:s19
[3] http://my.opera.com/arcfide/blog/2010/08/25/syntax-brain-twister

--
Programming is just another word for the lost art of thinking.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eli Barzilay  
View profile  
 More options Mar 17 2011, 1:49 am
Newsgroups: comp.lang.scheme
From: Eli Barzilay <e...@barzilay.org>
Date: Thu, 17 Mar 2011 01:49:03 -0400
Local: Thurs, Mar 17 2011 1:49 am
Subject: Re: Idiot's guide to Scheme macros?
"Aaron W. Hsu" <arcf...@sacrideo.us> writes:

> [...] and the with-syntax form allows a cleaner final syntax, so
> that you do not need to use quasisyntax and quasiunquote.

At least in the Racket case, `quasisyntax' is implemented using
`with-syntax'.  (If fact, it had `with-syntax' when plt switched to
`syntax-case' macros, and I made a feature request for something like
quasiquotes that make some uses easier.)

--
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eli Barzilay  
View profile  
 More options Mar 17 2011, 3:35 am
Newsgroups: comp.lang.scheme
From: Eli Barzilay <e...@barzilay.org>
Date: Thu, 17 Mar 2011 03:35:29 -0400
Local: Thurs, Mar 17 2011 3:35 am
Subject: Re: Idiot's guide to Scheme macros?

Marco Maggi <ma...@maggi.invalid> writes:
> 2. Learn the syntax-case library.

(`syntax-case' is not a library, it's just a way to deal with syntax
values via pattern matching.  (And I hope that you don't use "library"
as in "learn the implementation" -- that would be an overkill.))

> 3. Learn Rackets macro system.

Knowing about `syntax-case' should be enough for almost all practical
cases cases.

>   For syntax-rules: I suggest you to search for "syntax-rule
> tutorial" and  pick any of the short  introductions you find
> this  way,  just  to  get  you  started;  then  read  "JRM's
> Syntax-rules Primer  for the Merely  Eccentric"[1], which is
> long and should satisfy your needs.

That tutorial goes from relatively simple uses to complicated ones
that simulate computations using rewrite rules.  It's cute to know
that these things are available in a system as simple as
`syntax-rules', but when you have a "low level" macro system where you
define plain functions (instead of being limited to rewrite rules)
there's no need for that kind of obscure gymnastics.

> Also, to learn syntax-case one has to build a mental model of how
> the macro expander works, and it is totally opaque at first.

I very strongly disagree with this.  I consider myself sufficiently
fluent with `syntax-case' macros, and I know only a bit about the
implementation (including "how the macro expander works") -- and I'm
intentionally avoiding reading such details to keep my understanding
at the "user level".

[Because of this the following explanation is rough, but it should be
fine to understand how to use `syntax-case'.  No need to flame with
the 2000 mistakes I'm liable to make.]

The main idea with Racket's macro system (and probably with other
`syntax-case' systems) is that macros are syntax to syntax functions,
just like `defmacro', except that instead of raw s-expressions you're
dealing with syntax object.  This becomes very noticeable when
identifiers are handled: instead of dealing with symbols, you're
dealing with these syntax values (called "identifiers" in this case)
that are essentially a symbol and some opaque information that
represents the lexical scope for its source.  In several `syntax-case'
systems this is the only difference from `defmacro' macros, but in the
Racket case this applies to everything -- identifiers, numbers, other
immediate constants, function applications, etc -- they are all the
usual sexpr values that you're used to, except wrapped with additional
information.  Another thing that is unique to Racket is this extra
information: in addition to the opaque lexical context, there is also
source information and arbitrary properties (there are also
certificates, but that's ignorable for this level.).

With this in mind, explaining the rest is not too difficult:

* (syntax-source stx), (syntax-position stx), (syntax-line stx),
  (syntax-column stx) -- retrieve parts of the source information.

* (syntax-e stx) -- takes a syntax value and returns the value it
  "wraps".  For example, if `stx' is an identifier you'd get a symbol,
  and if it's a number you'd get the number etc.  If it's a
  parenthesized form, you'd get a list of syntax values for the
  subforms.  Note that the list can be improper, with the last
  element being a syntax object that contains a proper list.

* (syntax->list stx) -- since `syntax-e' might return an improper list
  for a list syntax, this utility makes things easier and will use
  `syntax-e' again in these cases and will return a proper list.  If
  the syntax is itself not a proper list, it returns #f.

* (syntax->datum stx) -- takes a syntax value and returns the plain
  s-expression that it holds.  This is done by recursive uses of
  `syntax-e'.  (It would be a simple definition.)

* (syntax-property stx prop) -- returns the given property value from
  stx, if any, and #f if none.  For example, try
    (syntax-property #'[foo] 'paren-shape)

* There is no accessor for the lexical scope (and you don't need one).

* To create a piece of syntax you use `datum->syntax', and you give it
  an s-expression which will be the "contents" of the resulting syntax
  object.  (The input can contain syntax values, which are left as
  is.)  But when you do that you need to give it the other bits --
  including the lexical context thing, which you have no access to.
  The way that's done is:

    (datum->syntax context-stx input-sexpr)

  This returns a syntax value that wraps the `input-sexpr' value,
  using the lexical scope from `context-stx'.  There is actually
  another optional argument that specifies the source (either using
  another syntax object, or as an explicit list), and another for
  copying the properties from, etc.  So a common thing to do when you
  want to create an unhygienic user-visible binding is:

    (datum->syntax something 'foo something something)

  where `something' is some syntax value that you get from the user
  input to the macro.  It makes a `foo' identifier that has the same
  lexical context information, same source, and same properties.

* There is also (quote-syntax blah) which creates a quoted syntax,
  with its lexical source from the place it appears.

* Finally, `define-syntax' does the magic of tying a name with a
  transformer function.

And that's almost everything that you need in order to write hygienic
(and non-hygienic) macros.  Very inconveniently.

For example, here's a simple `while' macro:

   (define-syntax (while stx)
     (define subs (syntax->list stx))
     (datum->syntax
      stx
      `(let loop ()
         (when ,(cadr subs)
           ,@(cddr subs)
           (loop)))
      stx))

which breaks like this:

  (define x 2)
  (let ([let 5])
    (while (< x 10) (printf "x = ~s\n" x) (set! x (add1 x))))

The problem is that all of those quoted names are getting the context
of the user input, which is not the right thing (it's close to a
defmacro).  To fix this, you need to `quote-syntax' all of these
identifiers, so they'll have the macro source instead of the input
source (to try this, you'll need (require (for-syntax racket/base)),
but that's a different story):

   (define-syntax (while stx)
     (define subs (syntax->list stx))
     (datum->syntax
      stx
      `(,(quote-syntax let) ,(quote-syntax loop) ()
         (,(quote-syntax when) ,(cadr subs)
           ,@(cddr subs)
           (,(quote-syntax loop))))
      stx))

But that's clearly insane...  More than being tedious, it's still
incorrect since all of those parens will have the user's lexical
context (which means that it will use the user's notion of function
application via the special `#%app' macro).  Instead of doing this, a
better approach would be to create the resulting syntax with the
lexical context of the macro source by changing just that argument:

   (define-syntax (while stx)
     (define subs (syntax->list stx))
     (datum->syntax
      (quote-syntax here)
      `(let loop ()
         (when ,(cadr subs)
           ,@(cddr subs)
           (loop)))
      stx))

And that's simple again, and works fine.

The problem is that it's tedious wrt to deconstructing the input
(which is trivial in this case), and wrt slapping together an output
value -- and that's where `syntax-case' comes in.  It addresses the
both by using pattern matching, where identifiers in patterns are
bound as "syntax patterns".  A new form is added -- `syntax' -- which
is similar to a `quote', except that (a) it actually quotes things
similarly to `quote-syntax', with the lexical context of the `syntax'
form; and (b) pattern variables are substituted with what they
matched.  The above macro becomes much easier:

   (define-syntax (while stx)
     (syntax-case stx ()
       [(_ test body ...)
        (syntax (let loop () (when test body ... (loop))))]))

The first line specifies that you want to match the `stx' input
syntax, and that you have no "keywords" (in the same sense as in
`syntax-rules').  The second line is the pattern that is matched
against this input -- with two pattern variables that match the second
subexpression and the sequence of expressions from the third and on.
(The first subexpression is matched against `_' which matches anything
and doesn't bind a pattern variable -- it's often not needed, since
it's just the macro name.)  The last line is the output, specified
using `syntax', which means that it's very similar to the previous
version where everything is given the lexical context of the macro and
the two pattern variables are replaced with the two matches (which
means a splicing subtitution for `body').

Now, say that you want an unhygienic user-visible piece of syntax.
For example, bind the always entertaining `it' thing to the test
result.  This:

   (define-syntax (while stx)
     (syntax-case stx ()
       [(_ test body ...)
        (syntax (let loop ()
                  (let ([it test])
                    (when it body ... (loop)))))]))

won't work because `it' has the macro source -- it's hygienic and
therefore not visible.  Instead, you need to use `datum->syntax' with
the user syntax:

   (define-syntax (while stx)
     (syntax-case stx ()
       [(_ test body ...)
        (let ([it (datum->syntax stx 'it)])
          (syntax (let loop ()
                    (let ([it test])
                      (when it body ... (loop))))))]))

But this doesn't really work since `it' needs to be bound as a pattern
variable rather than a plain binding.  `syntax-case' can be used here
again: (syntax-case <something> () [foo <body>]) will match `foo'
against the <something> syntax, and it will be bound as a pattern
variable in the <body>.  So:

   (define-syntax (while stx)
     (syntax-case stx ()
       [(_ test body ...)
        (syntax-case (datum->syntax stx 'it) ()
          [user-it
           (syntax (let loop ()
                     (let ([user-it test])
                       (when user-it body ... (loop)))))])]))

Finally, there are some more conveniences.  First,
...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eli Barzilay  
View profile  
 More options Mar 17 2011, 3:39 am
Newsgroups: comp.lang.scheme
From: Eli Barzilay <e...@barzilay.org>
Date: Thu, 17 Mar 2011 03:39:31 -0400
Local: Thurs, Mar 17 2011 3:39 am
Subject: Re: Idiot's guide to Scheme macros?
"Aaron W. Hsu" <arcf...@sacrideo.us> writes:

> [...] Racket is less forgiving in certain areas related to macro
> systems (though not its macro system proper) than Chez is, including
> libraries and phasing.

This would be similar to saying that Scheme is less forgiving than
JavaScript is when it comes to adding strings -- it throws an error
for (+ 1 "2"), instead of returning "12".  IMO (note the "M") think
that "less forgiving" in both cases is desirable in avoiding confusing
bugs.

--
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eli Barzilay  
View profile  
 More options Mar 17 2011, 3:54 am
Newsgroups: comp.lang.scheme
From: Eli Barzilay <e...@barzilay.org>
Date: Thu, 17 Mar 2011 03:54:55 -0400
Local: Thurs, Mar 17 2011 3:54 am
Subject: Re: Idiot's guide to Scheme macros?

Tim Bradshaw <t...@tfeb.org> writes:
> [...]

Did you look at the guide, BTW?

  http://docs.racket-lang.org/guide/macros.html

> The "things I want to do" are essentially introduce bindings which
> the user of the macro can see (which I think is the same thing as
> "not be hygenic"), so I want something like this to "work":

> (define-syntax bodging
>  (syntax-rules ()
>    ((bodging form ...)
>     (let ((x 1)) form ...))))

Hopefully the explanation I gave in the other post should clarify it.
But note that doing so is usually considered a bad thing, and can get
confusing with macros that have inputs that come from other macros.  A
more robust way to do this kind of thing in racket is to keep things
hygienic -- you define a new `it' (or `x' in the above) keyword that
is usually a syntax error, except when it's used inside your macro.  I
described this a while ago here:

  http://blog.racket-lang.org/2008/02/dirty-looking-hygiene.html

> I'm aware that there are things out there which essentially look
> like the CL macro system, but I don't want to use them as I already
> understand that (though, if they can be implemented in terms of
> syntax-case &c it might well be interesting to look at their
> implementation to see how they do it).

In the Racket case, the "defmacro" library does that -- you can see
its high level in "collects/mzlib/defmacro.rkt", and the actual work
is done in "collects/mzlib/private/dmhelp.rkt".  What it does is
convert the input syntax to a plain sexpr but keep a hash table that
maps the sexpr (and is subparts) to the corresponding syntax values.
Then, the macro function is applied on this sexpr.  Finally, pieces of
the resulting sexpr that are found in this hash table are replaced
with the original syntax that they came from, and the whole thing is
then turned back into syntax using `datum->syntax' with the input
syntax for lexical context.

--
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Tim Bradshaw  
View profile  
 More options Mar 17 2011, 6:43 am
Newsgroups: comp.lang.scheme
From: Tim Bradshaw <t...@tfeb.org>
Date: Thu, 17 Mar 2011 10:43:08 +0000
Local: Thurs, Mar 17 2011 6:43 am
Subject: Re: Idiot's guide to Scheme macros?
On 2011-03-17 07:54:55 +0000, Eli Barzilay said:

> Did you look at the guide, BTW?

>   http://docs.racket-lang.org/guide/macros.html

Yes, in fact that's how I learnt what I now know about syntax-rules and
so on.  I then got somewhat confused by the syntax-case stuff and was
too lazy to fight my way through it, though I think (thanks mostly to
responses here) I'm now in a good position to unconfuse myself.

Most of the problem, really, is that I know the CL macro system - which
is the FORTRAN IV of macro systems - so well that it's impeding my
understanding of how Scheme's work I think.

> Hopefully the explanation I gave in the other post should clarify it.
> But note that doing so is usually considered a bad thing, and can get
> confusing with macros that have inputs that come from other macros.  A
> more robust way to do this kind of thing in racket is to keep things
> hygienic -- you define a new `it' (or `x' in the above) keyword that
> is usually a syntax error, except when it's used inside your macro.  I
> described this a while ago here:

That's actually quite close to my target case, which is to be able to
emulate (for self-pedagogical purposes) a macro I have in CL which lets
you say:

(collecting
  ...
  (collect x)
  ...
  (foo (lambda (x) (collect x)))
  ...)

where COLLECT is a local macro (in the current CL implementation: it
should actually be a local function but I didn't understand that when I
wrote a very long time ago, hence the annoying wrapping-it-in-lambda
thing above) which will collect its argument into a list, with the
result of the whole form being the list.

In CL, COLLECT obviously needs to exist as a symbol even outside of the
macro: in the current implementation it does not have a global
definition, but it actually should have one which simply signals an
error.  So that's pretty like your example.

Once again thanks to everyone who's answered here: I didn't expect to
get such a lot of good answers.

--tim

PS please no-one write collecting/collect for me: the whole point is
that I want to understand how to do it, not that I actually need the
macro.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Tim Bradshaw  
View profile  
 More options Mar 17 2011, 2:42 pm
Newsgroups: comp.lang.scheme
From: Tim Bradshaw <t...@tfeb.org>
Date: Thu, 17 Mar 2011 18:42:43 +0000
Local: Thurs, Mar 17 2011 2:42 pm
Subject: Re: Idiot's guide to Scheme macros?
On 2011-03-16 15:49:17 +0000, Marco Maggi said:

> or more briefly but completely equivalent:

> (define-syntax bodging
>   (lambda (stx)
>     (syntax-case stx ()
>       ((bodging form ...)
>        #`(let ((#,(datum->syntax #'bodging 'x) 1))
>       form ...)))))

And the answer for my test case dirty macro is this:

(define (call/collecting thunk)
  ;; mindless reverse-the-list version
  (let ((s '()))
    (thunk (lambda (e)
             (set! s (cons e s))))
    (reverse s)))

(define-syntax (collecting stx)
  (syntax-case stx ()
    ((collecting)
     #'(quote ()))
    ((collecting form ...)
     #`(call/collecting (lambda (#,(datum->syntax stx 'collect))
                          form ...)))))

And now, for instance, (collecting (collect 1) (collect 2)) -> (1 2).

Which is delightfully easy.  There's obviously a lot to understand
here, but I'm making progress.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Thomas Munro  
View profile  
 More options Mar 17 2011, 5:39 pm
Newsgroups: comp.lang.scheme
From: Thomas Munro <thomas.mu...@gmail.com>
Date: Thu, 17 Mar 2011 14:39:55 -0700 (PDT)
Local: Thurs, Mar 17 2011 5:39 pm
Subject: Re: Idiot's guide to Scheme macros?
On Mar 16, 2:57 am, "Aaron W. Hsu" <arcf...@sacrideo.us> wrote:

> Indeed, any Scheme that supports syntax-case can have a form of defmacro.

Is the opposite true?  Can syntax-case be implemented on top of
defmacro?

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Marco Maggi  
View profile  
 More options Mar 18 2011, 4:31 am
Newsgroups: comp.lang.scheme
From: Marco Maggi <ma...@maggi.invalid>
Date: Fri, 18 Mar 2011 09:31:00 +0100
Subject: Re: Idiot's guide to Scheme macros?

Eli Barzilay wrote:
>> Also,  to learn  syntax-case one  has to  build  a mental
>> model of how the macro  expander works, and it is totally
>> opaque at first.

> I very strongly disagree with this.
> [...]
> And  that's almost everything  that you  need in  order to
> write   hygienic    (and   non-hygienic)   macros.    Very
> inconveniently.

Uff... Probably  unconsciously, you  make it sound  like "if
you do  not get it, you  do not deserve to  code in Scheme",
which is a bit annoying.  ;-)

  People  have difficulties  in  learning Scheme's  hygienic
macros, it is a fact for me.  Even if, at some point in your
life,   you   are  comfortable   in   using  an   "ordinary"
preprocessor (like  GNU m4), IMHO  there is very  little you
can   reuse  in   your  brain   from  past   experiences  in
non-esoteric  languages:  Scheme   hygienic  macros  are  on
another level.

My 2 cents.
--
Marco Maggi


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
David Banks  
View profile  
 More options Mar 18 2011, 4:40 am
Newsgroups: comp.lang.scheme
From: David Banks <amoe...@gmail.com>
Date: Fri, 18 Mar 2011 08:40:55 +0000
Local: Fri, Mar 18 2011 4:40 am
Subject: Re: Idiot's guide to Scheme macros?
On 17/03/11 07:35, Eli Barzilay wrote:

> [Because of this the following explanation is rough, but it should be
> fine to understand how to use `syntax-case'.  No need to flame with
> the 2000 mistakes I'm liable to make.]

> The main idea with Racket's macro system (and probably with other
> `syntax-case' systems)... <snip>

Thanks for this post Eli, it was the most useful explanation of macros
that I have yet read.

Cheers,
David


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Pascal Costanza  
View profile  
 More options Mar 18 2011, 4:52 am
Newsgroups: comp.lang.scheme
From: Pascal Costanza <p...@p-cos.net>
Date: Fri, 18 Mar 2011 09:52:24 +0100
Local: Fri, Mar 18 2011 4:52 am
Subject: Re: Idiot's guide to Scheme macros?
On 17/03/2011 22:39, Thomas Munro wrote:

> On Mar 16, 2:57 am, "Aaron W. Hsu"<arcf...@sacrideo.us>  wrote:
>> Indeed, any Scheme that supports syntax-case can have a form of defmacro.

> Is the opposite true?  Can syntax-case be implemented on top of
> defmacro?

This can be answered with a strong and resounding "maybe". ;)

See http://dx.doi.org/10.3217/jucs-016-02-0271

Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Pascal J. Bourguignon  
View profile  
 More options Mar 18 2011, 5:36 am
Newsgroups: comp.lang.scheme
From: "Pascal J. Bourguignon" <p...@informatimago.com>
Date: Fri, 18 Mar 2011 10:36:13 +0100
Local: Fri, Mar 18 2011 5:36 am
Subject: Re: Idiot's guide to Scheme macros?

Marco Maggi <ma...@maggi.invalid> writes:
> People have difficulties in learning Scheme's hygienic macros,
> it is a fact for me. Even if, at some point in your life, you are
> comfortable in using an "ordinary" preprocessor (like GNU m4),
> IMHO there is very little you can reuse in your brain from
> past experiences in non-esoteric languages: Scheme hygienic
> macros are on another level.

Not another level: another language.

That's what's so great with Common Lisp macros:
they're written in Common Lisp.

--
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Messages 1 - 25 of 37   Newer >
« Back to Discussions « Newer topic     Older topic »