In my recent work I found myself writing a lot of code that looked like the following:
(destructuring-bind (x y)
point
(destructuring-bind (x1 y1 w h)
frame
(let ((x2 (+ x1 w))
(y2 (+ y1 h)))
(and (>= x x1) (<= x x2) (>= y y1) (<= y y2)))))
The above example is a bit contrived, for effect, but hopefully conveys the general idea.
What I wanted was a Clojure style `let' which could destructure
inline. There was one Common Lisp implementation
(http://common-lisp.net/project/metabang-bind/), which had some nice
features, but it was bit much for my needs. So I came up with my own
lightweight bind macro (see below), which lets me rewrite the above
example as:
(bind (((x y) point)
((x1 y1 w h) frame)
(x2 (+ x1 w))
(y2 (+ y1 h)))
(and (>= x x1) (<= x x2) (>= y y1) (<= y y2)))
Way better, IMHO.
Oh, here's the `bind' macro in its entirety:
(defmacro bind (clauses &body body)
"This macro combines the behaviour of the forms `let*', `destructuring-bind',
and `multiple-value-bind', permitting the following style of binding form:
(bind (((:values m n) (values 10 20))
((a b &key (c 10)) '(1 2))
(x 5))
(+ x a b c m n))
=> 48
This is a more limited and lightweight implementation of some ideas from
metabang-bind (http://common-lisp.net/project/metabang-bind/)."
(cond
((null clauses) `(progn ,@body))
((and (listp (caar clauses)) (eq (caaar clauses) :values))
`(multiple-value-bind ,(cdaar clauses)
,@(cdar clauses)
(bind ,(cdr clauses) ,@body)))
((listp (caar clauses))
`(destructuring-bind ,(caar clauses)
,@(cdar clauses)
(bind ,(cdr clauses) ,@body)))
(t
`(let (,(car clauses))
(bind ,(cdr clauses) ,@body)))))