[plt-scheme] ML pattern programming macro in scheme

From: Paulo Jorge de Oliveira Cantante de Matos (pocm at netvisao.pt)
Date: Wed Mar 3 19:02:29 EST 2004

Dear all,

While studying SML through Paulson's book I just found nice to write
procedures whose arguments where some kind of pattern, based on lists...
so I though... da hell, maybe this could be useful in scheme. Since I
never heard about any implementation with this (didn't search much
also... heh) I implemented a very simple macro without any error
checking, however the results were nice. Is there any interest in a
macro like this in DrScheme, or around the scheme community? Am I
reinventing the wheel, since it is already done?

Ok, the code is as follows:
(define-macro define/pat
  (letrec ([getpath 
            (lambda (l)
              (letrec ([aux
                        (lambda (los f bindings)
                          (cond ([null? los]
                                ([symbol? (car los)]
                                 (aux (cdr los)
                                      (cons 'cdr (list f))
                                      (cons (list (car los) (cons 'car
(list f)))
                                ([list? (car los)]
                                 (append (aux (car los)
                                              (cons 'car (list f))
                                         (aux (cdr los)
                                              (cons 'cdr (list f))
                                (else (error "Unexpected case."))))])
                (aux l 'x null)))])
    (lambda (name pat . body)
      `(define ,name
         (lambda args
           (let ,(map (lambda (pair)
                        `(,(car pair)
                           (apply (lambda (x) ,(cadr pair)) args))) 
                      (getpath pat))
             , at body))))))

Ok, now, here are some nice simple tests from the SML book:
; Length of a vector
(define/pat lengthvec (x y)
            (sqrt (+ (* x x) (* y y))))

; Adds two vectors
(define/pat addvec ((x1 y1) (x2 y2))
            (list (+ x1 x2) (+ y1 y2)))

; Negates a vector
(define/pat negvec (x y)
            (list (- x) (- y)))

; Averages two numbers
(define/pat average (x y)
            (/ (+ x y) 2))

; Subtracts two vectors
(define/pat subvec (v1 v2)
            (addvec `(,v1 ,(negvec v2))))

; Distance between two vectors
(define/pat distance (pairvec)
            (lengthvec (subvec pairvec)))

; Scale a vector 
(define/pat scalevec (r (x y))
            (list (* r x) (* r y)))

; And now some testing:
(define vec1 '(2 3))
(define vec2 '(5 4))
(define vec3 '(-2 3))

(lengthvec vec1)
> 3.605551275463989
(lengthvec vec3)
> 3.605551275463989
(addvec `(,vec1 ,vec3))
> (0 6)
(negvec vec3)
> (2 -3)
(average vec2)
> 4 1/2
(subvec `(,vec1 ,vec2))
> (-3 -1)
(distance (list `(,vec1 ,vec2)))
> 3.1622776601683795
(scalevec `(3 ,vec2))
> (15 12)

I know there is some boring usage of quasiquote here, I think one can
find a way to make it easier to use define/pat, however, I've not looked
into it and I won't for some days since I'm having a lot of work. This
is just to let you now of some nice result so that you can comment about
this nice macro. :D At least, it made me happy! heheh



Paulo J. Matos : pocm [_at_] mega . ist . utl . pt
Instituto Superior Tecnico - Lisbon
Computer and Software Eng. - A.I.
 - > http://mega.ist.utl.pt/~pocm
        -> God had a deadline...
                So, he wrote it all in Lisp!

Posted on the users mailing list.