[plt-scheme] Pattern-matching macro chokes on conditional statement which would otherwise work.

From: Noel Welsh (noelwelsh at gmail.com)
Date: Sun Jan 20 10:37:20 EST 2008

Below is a working version (tested in 3.99).  The key error you were
making was conflating expansion time and evaluation time.  In
particular, you were trying to perform the test for an identifier at
evaluation time, not expansion time.  Of course this is too late -- by
the time the test is performed all expansion has occurred, so
erroneous statements like (let ([2 ...]) ...)  have been created.  To
perform the test at expansion time I switched to syntax-case and then
used a 'fender' expression to perform the test.  I slightly changed
the semantics of your match macro as it is necessary for the list of
value expressions to be available at expansion time, so that this list
can be traversed at expansion time.

Like Greg I found the tone of your emails arrogant and offensive.  As
Robby noted email is not an expressive medium and it is easy to cause
offense with poorly chosen words.  I suggest taking more care in
future to avoid antagonising your readers.


(define-syntax (ran-match stx)
  (syntax-case stx ()
    [(ran-match {vfirst vrest ...} {pfirst prest ...} body ...)
     (identifier? #'pfirst)
     #'(let ([pfirst vfirst])
         (ran-match (vrest ...) (prest ...) body ...))]
    [(ran-match (vfirst vrest ...) [pfirst prest ...] body ...)
     #'(if (eqv? pfirst vfirst)
           (ran-match (vrest ...) (prest ...) body ...)
           ;; Evalutates pfirst and vfirst twice
           (error (format "Datums ~a and ~a did not match" pfirst vfirst)))]
    [(ran-match () () body ...)
     #'(begin body ...)]))

(ran-match (1 2 3) (one 2 three)
  (display three))

(ran-match (1 2 3) (1 2 3) (display 3)) ;; should match perfectly and
display 3 on the terminal (it doesn't).
(ran-match (1 2 3) (one two three) (display 3)) ;; works perfectly,
and prints 3.
(ran-match (1 2 3) ('one 'two 'three) (display 'one)) ;; - This should
fail to match the pattern altogether, as symbols which are already
quoted are matched for equality, rather than used as identifiers as
above. This dies miserably without returning #f.
(ran-match (1 2 3) (one 2 three) (display three))

Posted on the users mailing list.