From: Mark Johnson
Subject: A simple pattern matching macro
Date: 
Message-ID: <86006@brunix.UUCP>
;;; The following is the code for a simple pattern matching macro.
;;; I would appreciate comments or suggestions.
;;;
;;; A match macro call has the form
;;;
;;;     (match expr pattern match-expr doesnt-match-expr)
;;;
;;; and its value is match-expr if expr matches pattern, and 
;;; doesnt-match-expr if it doesn't.
;;;
;;; Patterns are lists like ('define fn-name ('lambda args . body)).
;;; Quoted expressions specify an equal? match, whereas unquoted symbols
;;; function as pattern variables that match anything.  These symbols
;;; are locally bound during the matching process to the parts of
;;; expr that they match, and match-expr is evaluated in this lexical
;;; environment.  ? is an anonymous variable.
;;;
;;; Example: The following function translates standard scheme function
;;; definitions into mit style scheme functions definitions, and doesn't touch
;;; other forms.
;;;
;;; (defun (standard-to-mit form)
;;;   (match form ('define fn-name ('lambda args . body))
;;;     `(define (,fn-name . ,args) . ,body)
;;;     form))

(defmacro match (parameter pattern true-exp &optional (false-exp nil))
  (match-maker pattern parameter true-exp false-exp))

(defun match-maker (pattern parameter true-exp false-exp)
  (cond ((null pattern) `(if (null ,parameter) ,true-exp ,false-exp))
        ((numberp pattern) 
         `(if (and (numberp ,parameter) (= ,parameter ,pattern))
              ,true-exp
              ,false-exp))
        ((eq pattern '?) true-exp)
        ((symbolp pattern) `(let ((,pattern ,parameter)) ,true-exp))
        ((and (consp pattern) (eq (car pattern) 'quote)) 
         `(if (equal ',(cadr pattern) ,parameter) ,true-exp ,false-exp))
        ((consp pattern) 
         `(if (consp ,parameter)
              ,(match-maker (car pattern) `(car ,parameter)
                            (match-maker (cdr pattern) `(cdr ,parameter)
                                         true-exp false-exp)
                            false-exp)
              ,false-exp))
        (t (error "Unable to interpret the pattern ~S in MATCH macro" pattern))))

(defun standard-to-mit (form)
   (match form ('define fn-name ('lambda args . body))
     `(define (,fn-name . ,args) . ,body)
     form))
From: Jeff Dalton
Subject: Re: A simple pattern matching macro
Date: 
Message-ID: <5300@skye.ed.ac.uk>
In article <·····@brunix.UUCP> ··@cs.brown.edu (Mark Johnson) writes:
>;;; The following is the code for a simple pattern matching macro.
>;;; I would appreciate comments or suggestions.
>;;;
>;;; A match macro call has the form
>;;;
>;;;     (match expr pattern match-expr doesnt-match-expr)
>;;;
>;;; and its value is match-expr if expr matches pattern, and 
>;;; doesnt-match-expr if it doesn't.
>;;;
>;;; Patterns are lists like ('define fn-name ('lambda args . body)).
>;;; Quoted expressions specify an equal? match, whereas unquoted symbols
>;;; function as pattern variables that match anything.  These symbols
>;;; are locally bound during the matching process to the parts of
>;;; expr that they match, and match-expr is evaluated in this lexical
>;;; environment.  ? is an anonymous variable.
>;;;
>;;; Example: The following function translates standard scheme function
>;;; definitions into mit style scheme functions definitions, and doesn't touch
>;;; other forms.
>;;;
>;;; (defun (standard-to-mit form)
>;;;   (match form ('define fn-name ('lambda args . body))
>;;;     `(define (,fn-name . ,args) . ,body)
>;;;     form))

Binding Lisp variables to the matched elements is a good idea.
Something else worth considering is to use expressions for patterns,
as in some functional languages (such as ML).  That is, instead
of having a special notation for patterns, use an expression that
would construct a list of the right shape.  Your example would
become:

  (match form (list 'define fn-name (list* 'lambda args . body))
    `(define (,fn-name . ,args) . ,body)
    form)

or even:

  (match form `(define ,fn-name (lambda ,args . ,body))
    `(define (,fn-name . ,args) . ,body)
    form)

The back/quasiquote version is much easier in Scheme than in Common
Lisp, because Scheme defines what "`" reads as.  In Scheme, all you
need is to be able to compile quasiquote patterns, but in Common Lisp
you need to be able to recognize all of the different things backquote
reads as in different Common Lisps.  (Or else redefine the "`"
character macro, which may be more trouble than it's worth.)

-- jd