Email list hosting service & mailing list manager

Opaque syntax objects Michael Sperber (12 Aug 2005 15:18 UTC)
Re: Opaque syntax objects felix winkelmann (12 Aug 2005 20:22 UTC)
Re: Opaque syntax objects Jens Axel Søgaard (12 Aug 2005 23:20 UTC)
Re: Opaque syntax objects Andre van Tonder (13 Aug 2005 00:25 UTC)
Re: Opaque syntax objects Michael Sperber (13 Aug 2005 07:46 UTC)
Re: Opaque syntax objects Jens Axel Søgaard (14 Aug 2005 19:45 UTC)
Re: Opaque syntax objects Andre van Tonder (14 Aug 2005 20:22 UTC)
Re: Opaque syntax objects bear (14 Aug 2005 17:48 UTC)
Re: Opaque syntax objects Keith Wright (13 Aug 2005 07:31 UTC)
Re: Opaque syntax objects Michael Sperber (13 Aug 2005 12:33 UTC)
Re: Opaque syntax objects Jens Axel Søgaard (14 Aug 2005 20:27 UTC)

Re: Opaque syntax objects Jens Axel Søgaard 12 Aug 2005 23:19 UTC

felix winkelmann wrote:
> On 8/12/05, Michael Sperber <xxxxxx@informatik.uni-tuebingen.de> wrote:
>
>>The issue has come up in the discussion, but hasn't really been in the
>>focus yet:
>>
>>I'd like to suggest that compound expressions be represented by an
>>opaque type rather than by pairs.  This would ensure a modicum of
>>abstraction, and would *really* make comprehensive the ability of all
>>syntax objects to carry location information.  I've come to appreciate
>>this added layer of abstraction in PLT Scheme.

Representing syntax-objects using normal lists does breaks the
abstraction, and I too prefer the extra layer of abstraction.

> But wouldn't this completely break the (IMHO) rather practical ability
> to destructure arguments passed to macros via normal Scheme operators?

Keeping this abstraction doesn't make destructuring significantly more
impractical. Destructuring arguments using the pattern matching
capabilities of syntax-case is unchanged with both representations, and
in the case were it is neccessary to use normal Scheme operators, most
often a call to syntax->list, which turns a syntax-object representing a
list into a list of syntax-objects, is enough to solve the problem.

> What I like about srfi-72 is that I can write hygienic macros with (nearly)
> the same ease as in conventional Lisp-/quasiquote-style. In fact this is
> what I consider the most innovative feature for SRFI-72.

Since quote, quasiquote, unquote and unquote-splicing is used to
construct lists, one can introduce syntax, quasisyntax, unsyntax and
unsyntax-splicing to construct syntax-objects. The abbreviation #'
is a common abbreviation for syntax, and in analogy with this among
others PLT uses #´ #, #,@ for the rest.

As an example of a macro written using normal Scheme operators and
these syntactical abbreviations, I have taken the macro do-primes
from "Practical Common Lisp" p. 94.

The macro-call (do-primes var start end body ...) evaluates for
each prime between start and end the body expressions in an
environment, where the variable var is bound to the prime current
prime.

(define-syntax (do-primes2 stx)
   (let* ((form  (syntax->list stx))
          (var   (cadr form))
          (start (caddr form))
          (end   (cadddr form))
          (body  (cddddr form)))
     #`(do ((#,var (next-prime #,start) (next-prime (+ #,var 1))))
         ((> #,var #,end) 'done)
         #,@body)))

; prints: 2 5 7 done
(do-primes2 p 1 10
             (display p)
             (newline))

A macro whose expansion uses quasiquote to construct a list can
be hard to read (and write), if ordinary lists are used to represent
syntax. It is not immediately obvious whether a given quasiquote
is used to construct the expansion or is a part of the expansion
of a call to the macro.

For comparison I have included a version of the above macro,
where the destructuring is done by normal syntax-case pattern
matching.

/Jens Axel

; do-primes.scm

(define (prime? n)
   (cond
     ((even? n) (= n 2))
     (else      (let loop ((trial-divisor 3))
                  (cond
                    ((< n (* trial-divisor trial-divisor)) #t)
                    ((zero? (remainder n trial-divisor))   #f)
                    (else
                      (loop (+ trial-divisor 2))))))))

(define (next-prime n)
   (if (prime? (+ n 1))
       (+ n 1)
       (next-prime (+ n 1))))

(define-syntax (do-primes stx)
   (syntax-case stx ()
     ((do-primes var start end body ...)
      #'(do ((var (next-prime start) (next-prime (+ var 1))))
          ((> var end) 'done)
          body ...))))

(do-primes p 1 10
            (display p)
            (newline))

(define-syntax (do-primes2 stx)
   (let* ((form  (syntax->list stx))
          (var        (cadr form))
          (start      (caddr form))
          (end        (cadddr form))
          (body       (cddddr form)))
     #`(do ((#,var (next-prime #,start) (next-prime (+ #,var 1))))
         ((> #,var #,end) 'done)
         #,@body)))

(do-primes2 p 1 10
             (display p)
             (newline))

--
Jens Axel Søgaard