[alexandria-devel] DESTRUCTURE-CLAUSES - alexandria_destruct#9CF676.diff (1/1)

Tobias C Rittweiler tcr at freebits.de
Thu Apr 26 09:15:25 UTC 2012


In article 
<CADow0CpTq8ns8xx065Uk7P92-w98b6njBkzK4f9qUffh3iaqpw at mail.gmail.com>,
 Nikodemus Siivola <nikodemus at random-state.net> wrote:

> On 25 April 2012 16:47, Tobias C Rittweiler <tcr at 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 
, at 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





More information about the alexandria-devel mailing list