[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]
bindings)
([symbol? (car los)]
(aux (cdr los)
(cons 'cdr (list f))
(cons (list (car los) (cons 'car
(list f)))
bindings)))
([list? (car los)]
(append (aux (car los)
(cons 'car (list f))
null)
(aux (cdr los)
(cons 'cdr (list f))
bindings)))
(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
Cheers,
--
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!