In article CADow0CpTq8ns8xx065Uk7P92-w98b6njBkzK4f9qUffh3iaqpw@mail.gmail.com, Nikodemus Siivola nikodemus@random-state.net wrote:
On 25 April 2012 16:47, Tobias C Rittweiler tcr@freebits.de wrote:
I was pleased to discover that DESTRUCTURING-CASE made it into Alexandria meanwhile. Very nice! This allows me to share the little gem that I'm attaching with this posting. It's a handy macro to make writing macros like DEFPACKAGE, DEFGENERIC of DEFREADTABLE easy like a breeze.
Nice!
Unless I misread this, duplicate clauses cause the earlier one to be discarded? Signaling an error instead might be better,
Yes, that is true. I also regularly use the following macro in macro definitions:
;;; This is a macro for sake of nicer indentation of the format control. (defmacro assert-no-duplicates (list (&key test key) &body (format-control . format-args)) "If LIST contains duplicates, an error is signaled. FORMAT-CONTROL,
and FORMAT-ARGS are passed to ERROR along an enumeration of the
duplicated items." `(%assert-no-duplicates ,list ,test ,key ,format-control (list ,@format-args)))
(defun %assert-no-duplicates (list test key format-control format-args) (let* ((test (if test (ensure-function test) #'eql)) (no-dups (remove-duplicates list :test test :key key))) (unless (= (length list) (length no-dups)) (error "~@<~? ~:_Duplicates are:~:_ ~:I~{~S~^, ~:_~}~:>" format-control format-args (dolist (x no-dups list) (setq list (remove (if key (funcall key x) x) list :count 1 :test test :key key)))))))
E.g.
(defmacro defpackage (name &body clauses) (assert-no-duplicates clauses (:key #'car) "Found duplicates in the clauses passed to ~S." `(defpackage ,name)) (destructure-clauses clauses ((:uses &rest uses) ...) (expand-defpackage uses ...)))
Do you want me to provide that as a patch, too?
though a fairly common pattern might also be served by special casing clauses of the form
(:keyword &append stuff)
or something like that, which would cause duplicate clauses to have their contents merged.
I don't know. It invents unprecedented syntax for a not really common case. And the manual way doesn't seem that bad:
(destructure-clauses clauses ((:foo &rest xs1) (:bar &rest xs2) ...) (let ((xs (append xs1 xs2))) ...))
Or maybe that should be factored into a separate function MERGE-ALIST, for preprocessing the clauses?
function MERGE-ALIST keys alist &optional (merge #'append)
...or something along those lines?
That one seems useful on its own. How comes you think the merging of clause parameters is anything but a rare occasion anyhow?
T
T