From: Jean-Louis Leroy
Subject: Destructuring problem
Date: 
Message-ID: <m3og4qvq1l.fsf@enterprise.newedgeconcept>
I want to extract a particular keyword/argument pair from a list and
collect all the other keywords arguments in another list, for example:

        '(x :type integer)              -> (x integer nil)
        '(x :type integer :col "xx")    -> (x integer (:col "xx"))
        '(x :col "xx" :type integer)    -> (x integer (:col "xx"))

The simplest solution I could figure is:

(destructuring-bind (name &rest rest &key type &allow-other-keys)
    '(x :type int :col 2)
  (list name type
	(let ((cut (position :type rest)))
	  (concatenate 'list (subseq rest 0 cut)
		(subseq rest (+ 2 cut))))))

...but certainly there's got to be an easier way?
-- 
Jean-Louis Leroy
http://users.skynet.be/jll

From: Kent M Pitman
Subject: Re: Destructuring problem
Date: 
Message-ID: <sfwsnu2mzpi.fsf@world.std.com>
Jean-Louis Leroy <···@skynet.be> writes:

> I want to extract a particular keyword/argument pair from a list and
> collect all the other keywords arguments in another list, for example:
> 
>         '(x :type integer)              -> (x integer nil)
>         '(x :type integer :col "xx")    -> (x integer (:col "xx"))
>         '(x :col "xx" :type integer)    -> (x integer (:col "xx"))
> 
> The simplest solution I could figure is:
> 
> (destructuring-bind (name &rest rest &key type &allow-other-keys)
>     '(x :type int :col 2)
>   (list name type
> 	(let ((cut (position :type rest)))
> 	  (concatenate 'list (subseq rest 0 cut)
> 		(subseq rest (+ 2 cut))))))

This won't work if :type occurs in a value position, since position
isn't looking in only every other position like you want it to.

I think you want to write a loop that tries to find the appropriate tail
(since CL provides no tail-finding operations that skip elements in their
search, you will have to hand-craft it with lower-level primitives).  

You could, of course, write a general-purpose (find-key key plist) operation
that. returned you the tail of plist which begins with key.  If you had
that, then you could write something like:
   (let* ((var   (car list))
          (plist (cdr list))
          (type-loc (find-key :type plist)))
     (if (not type-loc) (error "No :type was specified.")
       `(,var (cadr type-loc)
         ,(append (ldiff plist type-loc) (cddr type-loc)))))
I didn't bother to write find-key, and so consequently I didn't test this.
I'll leave both as an "exercise to the reader".  But I'm pretty sure something
like this will work and that this has the general form of the solution you
were looking for.  In particular, I think this is the principal use of ldiff
that I've ever encountered--to splice a member-style result out of a list or
plist--so I'm happy to have an opportunity to point out its usefulness in this
regard.
From: Kent M Pitman
Subject: Re: Destructuring problem
Date: 
Message-ID: <sfwu2eipq7t.fsf@world.std.com>
Kent M Pitman <······@world.std.com> writes:

> I think you want to write a loop that tries to find the appropriate tail
> (since CL provides no tail-finding operations that skip elements in their
> search, you will have to hand-craft it with lower-level primitives).  

I spoke too soon. As Tunc Simsek points out, the tertiary result of
GET-PROPERTIES is the tail, which is adequate to the task of my FIND-KEY
function.  I've used that a number of times for this purpose--dunno why it
slipped my midn.  I also missed a comma in the example code.  Here's the fix...

   (defun reformat-list (list)
     (let* ((var   (car list))
            (plist (cdr list))
            (type-loc (nth-value 2 (get-properties plist '(:type)))))
       (if (not type-loc) (error "No :type was specified.")
         `(,var ,(cadr type-loc)
           ,(append (ldiff plist type-loc) (cddr type-loc))))))

   (reformat-list '(x :name "Ex" 
		      :type integer
		      :description "A simple counter."))
   => (X INTEGER (:NAME "Ex" :DESCRIPTION "A simple counter."))

(This time I did test it...)
From: Tunc Simsek
Subject: Re: Destructuring problem
Date: 
Message-ID: <Pine.SOL.4.10.10006241508310.2389-100000@tudor.EECS.Berkeley.EDU>
Perhaps something can be done with GET-PROPERTIES:

(multiple-value-bind (key
		      value
		      found)
   (get-properties '(:type)
                   '(x :type integer :col "xx"))
   ...)


Good luck,
Tunc

On 24 Jun 2000, Jean-Louis Leroy wrote:

> I want to extract a particular keyword/argument pair from a list and
> collect all the other keywords arguments in another list, for example:
> 
>         '(x :type integer)              -> (x integer nil)
>         '(x :type integer :col "xx")    -> (x integer (:col "xx"))
>         '(x :col "xx" :type integer)    -> (x integer (:col "xx"))
> 
> The simplest solution I could figure is:
> 
> (destructuring-bind (name &rest rest &key type &allow-other-keys)
>     '(x :type int :col 2)
>   (list name type
> 	(let ((cut (position :type rest)))
> 	  (concatenate 'list (subseq rest 0 cut)
> 		(subseq rest (+ 2 cut))))))
> 
> ...but certainly there's got to be an easier way?
> -- 
> Jean-Louis Leroy
> http://users.skynet.be/jll
> 
>