This is the mail archive of the kawa@sourceware.org mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: question about define-syntax



Inline comments.


On Feb 8, 2008, at 3:59 AM, Yaroslav Kavenchuk wrote:

The simplified example:

;; convert list to list of pairs

(define-syntax make-pair-list
 (syntax-rules ()
   ((_ any)
    (error "Broken arguments count for pair-list"))
   ((_ name value)
    (cons (cons name value) ()))
   ((_ name value . args)
    (cons (cons name value) (make-pair-list . args)))))

;; call function with list of pairs

;; this is wrong:
(define-syntax func-with-pairs
 (syntax-rules ()
   ((_ func . args)
    (func . (make-pair-list . args)))))
;; result of (func-with-pairs list 1 2 3 4)
;; is (#<macro make-pair-list> 1 2 3 4), not ((1 . 2) (3 . 4)

The macro expander is doing something like the following:


   (func-with-pairs list 1 2 3 4)
   ;; func-with-pairs is a syntactic keyword; expand expression
=> (list . (make-pair-list 1 2 3 4))
   ;; but the previous expression is equivalent to the following
=> (list make-pair-list 1 2 3 4)

Since make-pair-list is not in the first position of the syntax form, it never triggers expansion. The use of the dot notation confuses the situation, since it makes it look like make-pair-list will get expanded.

;; this is right
(define-syntax func-with-pairs
 (syntax-rules ()
   ((_ func . args)
    (apply func (make-pair-list . args)))))
;; but why need `apply`?

(func-with-pairs list 1 2 3 4) => (apply list (make-pair-list 1 2 3 4)) => (apply list (cons (cons 1 2) (cons (cons 3 4) ())))

How write macro without `apply`?

I'm still thinking how to do it simply with syntax-rules. If you know syntax-case (and yes, I know, that's a big "if"), it's a lot easier that way. I just got the following to work in PLT Scheme, but it's certainly going to need some modification to work in Kawa (sorry, I can't try it in Kawa just now):


(define-syntax func-with-pairs
  (lambda (stx)
    (syntax-case stx ()
      ((_ fn . rest)
       (odd? (length (syntax-object->datum #'rest)))
       (error "func-with-pairs must have an even number of arguments"))
      ((_ fn . rest)
       (with-syntax ((conses (make-pair-list #'rest)))
         (syntax
          (fn . conses)))))))

;; Kawa doesn't have define-for-syntax; just use define
(define-for-syntax (make-pair-list stx)
  (syntax-case stx ()
    (()
     (syntax ()))
    ((a b . rest)
     (with-syntax ((rest-conses (make-pair-list #'rest)))
       (syntax
        ((cons a b) . rest-conses))))))

Trying it at the REPL:

> (func-with-pairs list 1 2 3 4)
((1 . 2) (3 . 4))

> (require (lib "pretty.ss"))
> (pretty-print (syntax-object->datum (expand '(func-with-pairs list 1 2 3 4))))
(#%app
(#%top . list)
(#%app (#%top . cons) (#%datum . 1) (#%datum . 2))
(#%app (#%top . cons) (#%datum . 3) (#%datum . 4)))


The latter is exactly the same as the PLT primitive expansion of this:

(list (cons 1 2) (cons 3 4))

...which we can also verify:

> (pretty-print (syntax-object->datum (expand '(list (cons 1 2) (cons 3 4)))))
(#%app
(#%top . list)
(#%app (#%top . cons) (#%datum . 1) (#%datum . 2))
(#%app (#%top . cons) (#%datum . 3) (#%datum . 4)))


The lesson I've learned about macros in Scheme: syntax-case is really hard to learn in the short term, but easier in the long run than syntax-rules.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]