From: Jeff Cunningham
Subject: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.22.02.57.41.170466@cunningham.net>
The following function does what I want it to do: that is, it modifies
selected properties of a list of property lists. Its seems like a lot of
redundant typing. Is this a case where one should use a macro? Or is there
another way to write this more compactly?

(defun update-props (proplist &key
                    (prop1 nil prop1-set-p)
                    (prop2 nil prop2-set-p)
                    (prop3 nil prop3-set-p)
                    (prop4 nil prop4-set-p)
                    (prop5 nil prop5-set-p))
  "Modifies designated properties of a list of property lists"
  (labels ((update-term (prop)
             (when prop1-set-p
               (setf (getf prop :prop1) prop1))
             (when prop2-set-p
               (setf (getf prop :prop2) prop2))
             (when prop3-set-p
               (setf (getf prop :prop3) prop3))
             (when prop4-set-p
               (setf (getf prop :prop4) prop4))
             (when prop5-set-p
               (setf (getf prop :prop5) prop5))
             prop))
    (mapcar #'update-term proplist)))

;; TEST:
(defparameter *test* '(((:prop1 T) :prop1 "hi" :prop5 'bar)))
(print (update-props *test* :prop1 nil :prop2 "abc" :prop3 'foo))

;; ((:PROP3 FOO :PROP2 "abc" :PROP1 NIL (:PROP1 T) :PROP1 "hi" :PROP5 'BAR))

Thanks
--jeff cunningham

From: Peter Seibel
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <m2d5o6verw.fsf@gigamonkeys.com>
Jeff Cunningham <·······@cunningham.net> writes:

> The following function does what I want it to do: that is, it modifies
> selected properties of a list of property lists. Its seems like a lot of
> redundant typing. Is this a case where one should use a macro? Or is there
> another way to write this more compactly?
>
> (defun update-props (proplist &key
>                     (prop1 nil prop1-set-p)
>                     (prop2 nil prop2-set-p)
>                     (prop3 nil prop3-set-p)
>                     (prop4 nil prop4-set-p)
>                     (prop5 nil prop5-set-p))
>   "Modifies designated properties of a list of property lists"
>   (labels ((update-term (prop)
>              (when prop1-set-p
>                (setf (getf prop :prop1) prop1))
>              (when prop2-set-p
>                (setf (getf prop :prop2) prop2))
>              (when prop3-set-p
>                (setf (getf prop :prop3) prop3))
>              (when prop4-set-p
>                (setf (getf prop :prop4) prop4))
>              (when prop5-set-p
>                (setf (getf prop :prop5) prop5))
>              prop))
>     (mapcar #'update-term proplist)))

  (defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
    (loop for (key value) on new-values by #'cddr do
      (setf (getf plist key) value))
    plist)

If you can live without the argument checking you can leave out the &key params.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.22.03.36.59.217641@cunningham.net>
On Mon, 22 Aug 2005 03:20:20 +0000, Peter Seibel wrote:


>   (defun update-properties (plist &rest new-values &key prop1 prop2
>   prop3 prop4 prop5)
>     (loop for (key value) on new-values by #'cddr do
>       (setf (getf plist key) value))
>     plist)
> 
> If you can live without the argument checking you can leave out the &key
> params.

Unfortunately, I can't. But - wow - that's much more compact anyway. I
guess I'm going to have to break down and learn how to use loop. That's
pretty slick.

Thanks!

-jeff cunningham
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.22.03.43.02.35595@cunningham.net>
On Mon, 22 Aug 2005 03:20:20 +0000, Peter Seibel wrote:

> Jeff Cunningham <·······@cunningham.net> writes:
> 
>> The following function does what I want it to do: that is, it modifies
>> selected properties of a list of property lists. Its seems like a lot of
>> redundant typing. Is this a case where one should use a macro? Or is there
>> another way to write this more compactly?
>>
>> (defun update-props (proplist &key
>>                     (prop1 nil prop1-set-p)
>>                     (prop2 nil prop2-set-p)
>>                     (prop3 nil prop3-set-p)
>>                     (prop4 nil prop4-set-p)
>>                     (prop5 nil prop5-set-p))
>>   "Modifies designated properties of a list of property lists"
>>   (labels ((update-term (prop)
>>              (when prop1-set-p
>>                (setf (getf prop :prop1) prop1))
>>              (when prop2-set-p
>>                (setf (getf prop :prop2) prop2))
>>              (when prop3-set-p
>>                (setf (getf prop :prop3) prop3))
>>              (when prop4-set-p
>>                (setf (getf prop :prop4) prop4))
>>              (when prop5-set-p
>>                (setf (getf prop :prop5) prop5))
>>              prop))
>>     (mapcar #'update-term proplist)))
> 
>   (defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
>     (loop for (key value) on new-values by #'cddr do
>       (setf (getf plist key) value))
>     plist)
> 
> If you can live without the argument checking you can leave out the &key params.
> 
> -Peter



Hmmm. They don't produce the same results. If I use this list as input:

(defparameter *test* '((:prop1 T) (:prop1 "hi" :prop5 'bar)))

I get these two outputs: (first from my code, second from yours)

((:PROP3 FOO :PROP2 "abc" :PROP1 NIL)
 (:PROP3 FOO :PROP2 "abc" :PROP1 NIL :PROP5 'BAR)) 

(:PROP3 FOO :PROP2 "abc" :PROP1 NIL (:PROP1 NIL) (:PROP1 NIL :PROP5 'BAR)) 

--jeff
From: Peter Seibel
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <m28xyuv7sm.fsf@gigamonkeys.com>
Jeff Cunningham <·······@cunningham.net> writes:

> On Mon, 22 Aug 2005 03:20:20 +0000, Peter Seibel wrote:
>
>> Jeff Cunningham <·······@cunningham.net> writes:
>> 
>>> The following function does what I want it to do: that is, it modifies
>>> selected properties of a list of property lists. Its seems like a lot of
>>> redundant typing. Is this a case where one should use a macro? Or is there
>>> another way to write this more compactly?
>>>
>>> (defun update-props (proplist &key
>>>                     (prop1 nil prop1-set-p)
>>>                     (prop2 nil prop2-set-p)
>>>                     (prop3 nil prop3-set-p)
>>>                     (prop4 nil prop4-set-p)
>>>                     (prop5 nil prop5-set-p))
>>>   "Modifies designated properties of a list of property lists"
>>>   (labels ((update-term (prop)
>>>              (when prop1-set-p
>>>                (setf (getf prop :prop1) prop1))
>>>              (when prop2-set-p
>>>                (setf (getf prop :prop2) prop2))
>>>              (when prop3-set-p
>>>                (setf (getf prop :prop3) prop3))
>>>              (when prop4-set-p
>>>                (setf (getf prop :prop4) prop4))
>>>              (when prop5-set-p
>>>                (setf (getf prop :prop5) prop5))
>>>              prop))
>>>     (mapcar #'update-term proplist)))
>> 
>>   (defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
>>     (loop for (key value) on new-values by #'cddr do
>>       (setf (getf plist key) value))
>>     plist)
>> 
>> If you can live without the argument checking you can leave out the &key params.
>> 
>> -Peter
>
>
>
> Hmmm. They don't produce the same results. If I use this list as input:
>
> (defparameter *test* '((:prop1 T) (:prop1 "hi" :prop5 'bar)))

I'm not sure how you mean you use this as input. Do you do something like:

 (apply #'update-props *test*)

?  

> I get these two outputs: (first from my code, second from yours)
>
> ((:PROP3 FOO :PROP2 "abc" :PROP1 NIL)
>  (:PROP3 FOO :PROP2 "abc" :PROP1 NIL :PROP5 'BAR)) 
>
> (:PROP3 FOO :PROP2 "abc" :PROP1 NIL (:PROP1 NIL) (:PROP1 NIL :PROP5 'BAR)) 

Eh? Where ore those :prop2 and :prop3 values coming from. I don't
think you're doing what you think you're doing. Maybe show us the
actual REPL interaction.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.22.15.32.11.769702@cunningham.net>
On Mon, 22 Aug 2005 05:51:05 +0000, Peter Seibel wrote:

> 
> Eh? Where ore those :prop2 and :prop3 values coming from. I don't
> think you're doing what you think you're doing. Maybe show us the
> actual REPL interaction.
> 

No doubt you are right. Here's the exact code:

(defun update-props (proplist &key
                    (prop1 nil prop1-set-p)
                    (prop2 nil prop2-set-p)
                    (prop3 nil prop3-set-p)
                    (prop4 nil prop4-set-p)
                    (prop5 nil prop5-set-p))
  "Modifies designated properties of a list of property lists"
  (labels ((update-term (prop)
             (when prop1-set-p
               (setf (getf prop :prop1) prop1))
             (when prop2-set-p
               (setf (getf prop :prop2) prop2))
             (when prop3-set-p
               (setf (getf prop :prop3) prop3))
             (when prop4-set-p
               (setf (getf prop :prop4) prop4))
             (when prop5-set-p
               (setf (getf prop :prop5) prop5))
             prop))
    (mapcar #'update-term proplist)))

;; According to P. Seibel, this is the same thing:
(defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
    (loop for (key value) on new-values by #'cddr do
      (setf (getf plist key) value))
    plist)

;; TEST:
(defparameter *test* '((:prop1 T) (:prop1 "hi" :prop5 'bar)))
(format t "~s~2%" (update-props *test* :prop1 nil :prop2 "abc" :prop3
'foo)) 
(format t "~s~%" (update-properties *test* :prop1 nil :prop2 "abc"
:prop3 'foo))


And here's the copied REPL result when I run it:

; In: DEFUN UPDATE-PROPERTIES

;   (DEFUN UPDATE-PROPERTIES (PLIST &REST NEW-VALUES &KEY PROP1 ...)
;     (LOOP # # # ...)
;     PLIST)
; Note: Variable PROP1 defined but never used.
; 
; Note: Variable PROP2 defined but never used.
; 
; Note: Variable PROP3 defined but never used.
; 
; Note: Variable PROP4 defined but never used.
; 
; Note: Variable PROP5 defined but never used.
; 

; Compilation unit finished.
;   5 notes

; /home/jcunningham/projects/problem.x86f written.
; Compilation finished in 0:00:01.
; Loading #P"/home/jcunningham/projects/problem.x86f".
((:PROP3 FOO :PROP2 "abc" :PROP1 NIL)
 (:PROP3 FOO :PROP2 "abc" :PROP1 NIL :PROP5 'BAR))

(:PROP3 FOO :PROP2 "abc" :PROP1 NIL (:PROP1 NIL) (:PROP1 NIL :PROP5 'BAR))

--jeff
From: Peter Seibel
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <m24q9hvqih.fsf@gigamonkeys.com>
Jeff Cunningham <·······@cunningham.net> writes:

> On Mon, 22 Aug 2005 05:51:05 +0000, Peter Seibel wrote:
>
>> 
>> Eh? Where ore those :prop2 and :prop3 values coming from. I don't
>> think you're doing what you think you're doing. Maybe show us the
>> actual REPL interaction.
>> 
>
> No doubt you are right. Here's the exact code:
>
> (defun update-props (proplist &key
>                     (prop1 nil prop1-set-p)
>                     (prop2 nil prop2-set-p)
>                     (prop3 nil prop3-set-p)
>                     (prop4 nil prop4-set-p)
>                     (prop5 nil prop5-set-p))
>   "Modifies designated properties of a list of property lists"
>   (labels ((update-term (prop)
>              (when prop1-set-p
>                (setf (getf prop :prop1) prop1))
>              (when prop2-set-p
>                (setf (getf prop :prop2) prop2))
>              (when prop3-set-p
>                (setf (getf prop :prop3) prop3))
>              (when prop4-set-p
>                (setf (getf prop :prop4) prop4))
>              (when prop5-set-p
>                (setf (getf prop :prop5) prop5))
>              prop))
>     (mapcar #'update-term proplist)))
>
> ;; According to P. Seibel, this is the same thing:
> (defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
>     (loop for (key value) on new-values by #'cddr do
>       (setf (getf plist key) value))
>     plist)
>
> ;; TEST:
> (defparameter *test* '((:prop1 T) (:prop1 "hi" :prop5 'bar)))
> (format t "~s~2%" (update-props *test* :prop1 nil :prop2 "abc" :prop3
> 'foo)) 
> (format t "~s~%" (update-properties *test* :prop1 nil :prop2 "abc"
> :prop3 'foo))

Okay, to *test*, as Wade pointed out is not a plist. I plist should
just be a list of alternating symbols and values. You can't use GETF
on *test* as it stands and get any kind of reasonable results.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.23.05.50.28.96409@cunningham.net>
On Mon, 22 Aug 2005 17:19:03 +0000, Peter Seibel wrote:

> Jeff Cunningham <·······@cunningham.net> writes:
> 
>> On Mon, 22 Aug 2005 05:51:05 +0000, Peter Seibel wrote:
>>
>>> 
>>> Eh? Where ore those :prop2 and :prop3 values coming from. I don't
>>> think you're doing what you think you're doing. Maybe show us the
>>> actual REPL interaction.
>>> 
>>
>> No doubt you are right. Here's the exact code:
>>
>> (defun update-props (proplist &key
>>                     (prop1 nil prop1-set-p)
>>                     (prop2 nil prop2-set-p)
>>                     (prop3 nil prop3-set-p)
>>                     (prop4 nil prop4-set-p)
>>                     (prop5 nil prop5-set-p))
>>   "Modifies designated properties of a list of property lists"
>>   (labels ((update-term (prop)
>>              (when prop1-set-p
>>                (setf (getf prop :prop1) prop1))
>>              (when prop2-set-p
>>                (setf (getf prop :prop2) prop2))
>>              (when prop3-set-p
>>                (setf (getf prop :prop3) prop3))
>>              (when prop4-set-p
>>                (setf (getf prop :prop4) prop4))
>>              (when prop5-set-p
>>                (setf (getf prop :prop5) prop5))
>>              prop))
>>     (mapcar #'update-term proplist)))
>>
>> ;; According to P. Seibel, this is the same thing:
>> (defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
>>     (loop for (key value) on new-values by #'cddr do
>>       (setf (getf plist key) value))
>>     plist)
>>
>> ;; TEST:
>> (defparameter *test* '((:prop1 T) (:prop1 "hi" :prop5 'bar)))
>> (format t "~s~2%" (update-props *test* :prop1 nil :prop2 "abc" :prop3
>> 'foo)) 
>> (format t "~s~%" (update-properties *test* :prop1 nil :prop2 "abc"
>> :prop3 'foo))
> 
> Okay, to *test*, as Wade pointed out is not a plist. I plist should
> just be a list of alternating symbols and values. You can't use GETF
> on *test* as it stands and get any kind of reasonable results.
> 
> -Peter

I didn't mean to say *test* was a plist. Its a list of plists. That's
why I'm using the mapcar to walk through it. The idea is that each plist
has the update-props function applied to it in turn. Note my comment in
the code:

>   "Modifies designated properties of a list of property lists"

So my question still stands: is there a simplier way to write the
update-props function so it does what mine does - which is highly
structured and repetitive. I'm pretty new to lisp and it seems like the
kind of thing you should be able to reduce to a macro or something if you
know more than I do. Your idea with the loop looks promising, but it
doesn't behave properly yet. 

-jeff
From: Tayssir John Gabbour
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <1124815315.646993.37690@g14g2000cwa.googlegroups.com>
Jeff Cunningham wrote:
> On Mon, 22 Aug 2005 17:19:03 +0000, Peter Seibel wrote:
> > Jeff Cunningham <·······@cunningham.net> writes:
> >> On Mon, 22 Aug 2005 05:51:05 +0000, Peter Seibel wrote:
> >>> Eh? Where ore those :prop2 and :prop3 values coming from. I don't
> >>> think you're doing what you think you're doing. Maybe show us the
> >>> actual REPL interaction.
> >>
> >> No doubt you are right. Here's the exact code:
> >>
> >> (defun update-props (proplist &key
> >>                     (prop1 nil prop1-set-p)
> >>                     (prop2 nil prop2-set-p)
> >>                     (prop3 nil prop3-set-p)
> >>                     (prop4 nil prop4-set-p)
> >>                     (prop5 nil prop5-set-p))
> >>   "Modifies designated properties of a list of property lists"
> >>   (labels ((update-term (prop)
> >>              (when prop1-set-p
> >>                (setf (getf prop :prop1) prop1))
> >>              (when prop2-set-p
> >>                (setf (getf prop :prop2) prop2))
> >>              (when prop3-set-p
> >>                (setf (getf prop :prop3) prop3))
> >>              (when prop4-set-p
> >>                (setf (getf prop :prop4) prop4))
> >>              (when prop5-set-p
> >>                (setf (getf prop :prop5) prop5))
> >>              prop))
> >>     (mapcar #'update-term proplist)))
> >>
> >> ;; According to P. Seibel, this is the same thing:
> >> (defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
> >>     (loop for (key value) on new-values by #'cddr do
> >>       (setf (getf plist key) value))
> >>     plist)
> >>
> >> ;; TEST:
> >> (defparameter *test* '((:prop1 T) (:prop1 "hi" :prop5 'bar)))
> >> (format t "~s~2%" (update-props *test* :prop1 nil :prop2 "abc" :prop3
> >> 'foo))
> >> (format t "~s~%" (update-properties *test* :prop1 nil :prop2 "abc"
> >> :prop3 'foo))
> >
> > Okay, to *test*, as Wade pointed out is not a plist. I plist should
> > just be a list of alternating symbols and values. You can't use GETF
> > on *test* as it stands and get any kind of reasonable results.
> >
> > -Peter
>
> I didn't mean to say *test* was a plist. Its a list of plists. That's
> why I'm using the mapcar to walk through it. The idea is that each plist
> has the update-props function applied to it in turn. Note my comment in
> the code:
>
> >   "Modifies designated properties of a list of property lists"
>
> So my question still stands: is there a simplier way to write the
> update-props function so it does what mine does - which is highly
> structured and repetitive. I'm pretty new to lisp and it seems like the
> kind of thing you should be able to reduce to a macro or something if you
> know more than I do. Your idea with the loop looks promising, but it
> doesn't behave properly yet.

Peter's code updates one plist. You want something which updates a list
of plists. So you just run his code over each element of your list of
plists. (Using mapcar or whatever.)

You can use FLET instead of LABELS, since it's not recursively calling
itself.

Also, you may not want to use a &REST parameter for the new values, but
rather just have them be in one plist that you pass in as a parameter.
The reasoning is, you might want to add more parameters to the
function. (Such as a flag which says it shouldn't update one of your
plists if it doesn't contain those keys.)

Keep in mind that "destructively modifying" NIL plists doesn't work.
They're not mutable enough. (Hmm, that's a Lisp Gotcha that should be
put on the wiki...)


Tayssir
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.24.02.26.47.28544@cunningham.net>
On Tue, 23 Aug 2005 09:41:55 -0700, Tayssir John Gabbour wrote:
> 
> You can use FLET instead of LABELS, since it's not recursively calling
> itself.
> 
> Also, you may not want to use a &REST parameter for the new values, but
> rather just have them be in one plist that you pass in as a parameter.
> The reasoning is, you might want to add more parameters to the
> function. (Such as a flag which says it shouldn't update one of your
> plists if it doesn't contain those keys.)
> 
> Keep in mind that "destructively modifying" NIL plists doesn't work.
> They're not mutable enough. (Hmm, that's a Lisp Gotcha that should be
> put on the wiki...)
> 
> 
> Tayssir

I never think of flet. Good idea. Just out of curiousity, is there an
advantage (like less machinery?). 

I don't understand why Peter uses the &rest parameter and the key
parameters. It seems like you could keep the &rest and toss the keys the
way he's doing it, but I'm going to experiment. I like your idea of
entering them as keys, but would it work the same way? 

About destructively modifying nil plists, I think you mean that this won't
work with a NIL plist, right? I think I knew that. In my application it
isn't a problem, but its always worth keeping in mind. 

Thanks for your help.
-jeff
From: Tayssir John Gabbour
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <1124855685.119648.121150@g47g2000cwa.googlegroups.com>
Jeff Cunningham wrote:
> On Tue, 23 Aug 2005 09:41:55 -0700, Tayssir John Gabbour wrote:
> > Also, you may not want to use a &REST parameter for the new values, but
> > rather just have them be in one plist that you pass in as a parameter.
> > The reasoning is, you might want to add more parameters to the
> > function. (Such as a flag which says it shouldn't update one of your
> > plists if it doesn't contain those keys.)
>
> I don't understand why Peter uses the &rest parameter and the key
> parameters. It seems like you could keep the &rest and toss the keys the
> way he's doing it, but I'm going to experiment.

Your original code signalled an error when someone entered a keyword
that wasn't in :prop1 to :prop6. Peter kept to that, showing off a
handy param checking technique.


> > Also, you may not want to use a &REST parameter for the new values, but
> > rather just have them be in one plist that you pass in as a parameter.
> > The reasoning is, you might want to add more parameters to the
> > function. (Such as a flag which says it shouldn't update one of your
> > plists if it doesn't contain those keys.)
>
> I like your idea of entering them as keys, but would it work the same way?

I was unclear. I meant something like:
  (defun update-properties (list-of-plists newprops) ; ....

instead of:
  (defun update-properties (list-of-plists &rest newprops) ; ...

That way, you can easily extend this function with extra keyword
parameters and whatnot. But whatever floats your boat.


> > You can use FLET instead of LABELS, since it's not recursively calling
> > itself.
>
> I never think of flet. Good idea. Just out of curiousity, is there an
> advantage (like less machinery?).

Yes, Paul Dietz once pointed out it can be a bit more efficient in some
implementations, though I'm sure he didn't mean that as a reason to
seriously prefer either one in normal use.

Some pros --

FLET:
* Considered more readable and simpler by people who immediately look
for a self-recursion when confronted with LABELS.
* People like a recommended CLtL2 pronunciation ("flay"). This happens
to be a big deal for some.
(Oy vey.)

LABELS:
* Works like DEFUN.
* FLET can be surprising in cases like:

(defun foo ()
  t)

(flet ((foo ()
         (foo)))
  (foo))  ; You might expect an infinite loop here...

=> t


While I've heard guesses that slightly more people use FLET by default
than LABELS, it's up to you...


Tayssir
From: Peter Seibel
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <m2ll2srp04.fsf@gigamonkeys.com>
Jeff Cunningham <·······@cunningham.net> writes:

> I don't understand why Peter uses the &rest parameter and the key
> parameters. It seems like you could keep the &rest and toss the keys the
> way he's doing it,

I mentioned that in passing in my first post (the one with the busted
code). If you specify &key in the parameter list then you get checking
that you don't pass other keyword arguments. With just &rest it'll
accept any arguments. Originally you said you wanted the argument
checking.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.25.02.16.39.774902@cunningham.net>
On Wed, 24 Aug 2005 03:29:47 +0000, Peter Seibel wrote:

> Jeff Cunningham <·······@cunningham.net> writes:
> 
>> I don't understand why Peter uses the &rest parameter and the key
>> parameters. It seems like you could keep the &rest and toss the keys
>> the way he's doing it,
> 
> I mentioned that in passing in my first post (the one with the busted
> code). If you specify &key in the parameter list then you get checking
> that you don't pass other keyword arguments. With just &rest it'll
> accept any arguments. Originally you said you wanted the argument
> checking.
> 
> -Peter

I took yours apart and see how it works. That's very cool! But now, if I
tied your right arm behind your back and said you couldn't use 'loop,
would this be a reasonable implementation of the inner loop?:

(defun ps-update-props (plist &rest newprops)
  (loop for (prop value) on newprops by #'cddr do
	(setf (getf plist prop) value)
	finally (return plist)))

(defun my-update-props (plist &rest newprops)
  (if (null newprops)
      plist
      (progn
	(setf (getf plist (car newprops)) (cadr newprops)) 
        (apply #'my-update-props plist (cddr newprops)))))

-jeff
From: Peter Seibel
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <m2fysysnjx.fsf@gigamonkeys.com>
Jeff Cunningham <·······@cunningham.net> writes:

> On Wed, 24 Aug 2005 03:29:47 +0000, Peter Seibel wrote:
>
>> Jeff Cunningham <·······@cunningham.net> writes:
>> 
>>> I don't understand why Peter uses the &rest parameter and the key
>>> parameters. It seems like you could keep the &rest and toss the keys
>>> the way he's doing it,
>> 
>> I mentioned that in passing in my first post (the one with the busted
>> code). If you specify &key in the parameter list then you get checking
>> that you don't pass other keyword arguments. With just &rest it'll
>> accept any arguments. Originally you said you wanted the argument
>> checking.
>> 
>> -Peter
>
> I took yours apart and see how it works. That's very cool! But now,
> if I tied your right arm behind your back and said you couldn't use
> 'loop, would this be a reasonable implementation of the inner loop?:
>
> (defun ps-update-props (plist &rest newprops)
>   (loop for (prop value) on newprops by #'cddr do
> 	(setf (getf plist prop) value)
> 	finally (return plist)))
>
> (defun my-update-props (plist &rest newprops)
>   (if (null newprops)
>       plist
>       (progn
> 	(setf (getf plist (car newprops)) (cadr newprops)) 
>         (apply #'my-update-props plist (cddr newprops)))))

Sure. Though keep in mind that Common Lisp implementations are not
required to compile tail calls so they take finite stack so your
version could use as many stack frames as half the length of
NEWPROPS. Which probably doesn't matter. Just for grins, here are a
few other possibilities:

  (defun update-props (plist &rest newprops)
    (if newprops
      (destructuring-bind (key value &rest rest) newprops
        (setf (getf plist key) value)
        (apply #'update-props plist rest))
      plist))

  (defun update-props (plist &rest newprops)
    (do ((newprops newprops (cddr newprops)))
        ((endp newprops) plist)
      (setf (getf plist (first newprops)) (second newprops))))

  (defun update-props (plist &rest newprops)
    (loop (when (endp newprops) (return plist))
       (destructuring-bind (k v &rest rest) newprops
         (setf (getf plist k) v newprops rest))))

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.25.14.56.31.641205@cunningham.net>
On Thu, 25 Aug 2005 03:28:04 +0000, Peter Seibel wrote:

> Jeff Cunningham <·······@cunningham.net> writes:
>> I took yours apart and see how it works. That's very cool! But now,
>> if I tied your right arm behind your back and said you couldn't use
>> 'loop, would this be a reasonable implementation of the inner loop?:
>>
>> (defun ps-update-props (plist &rest newprops)
>>   (loop for (prop value) on newprops by #'cddr do
>> 	(setf (getf plist prop) value)
>> 	finally (return plist)))
>>
>> (defun my-update-props (plist &rest newprops)
>>   (if (null newprops)
>>       plist
>>       (progn
>> 	(setf (getf plist (car newprops)) (cadr newprops)) 
>>         (apply #'my-update-props plist (cddr newprops)))))
> 
> Sure. Though keep in mind that Common Lisp implementations are not
> required to compile tail calls so they take finite stack so your
> version could use as many stack frames as half the length of
> NEWPROPS. Which probably doesn't matter. Just for grins, here are a

Wow. Important saftey tip. Now I have to do some thinking about where all
I've been using tail recursion. 


> few other possibilities:
> 
>   (defun update-props (plist &rest newprops)
>     (if newprops
>       (destructuring-bind (key value &rest rest) newprops
>         (setf (getf plist key) value)
>         (apply #'update-props plist rest))
>       plist))
> 
>   (defun update-props (plist &rest newprops)
>     (do ((newprops newprops (cddr newprops)))
>         ((endp newprops) plist)
>       (setf (getf plist (first newprops)) (second newprops))))
> 
>   (defun update-props (plist &rest newprops)
>     (loop (when (endp newprops) (return plist))
>        (destructuring-bind (k v &rest rest) newprops
>          (setf (getf plist k) v newprops rest))))
> 
> -Peter

This has been most illuminating. Much obliged.

-jeff
From: Joe Marshall
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pss2uj6r.fsf@ccs.neu.edu>
Jeff Cunningham <·······@cunningham.net> writes:

> On Thu, 25 Aug 2005 03:28:04 +0000, Peter Seibel wrote:
>>
>> Sure. Though keep in mind that Common Lisp implementations are not
>> required to compile tail calls so they take finite stack so your
>> version could use as many stack frames as half the length of
>> NEWPROPS. Which probably doesn't matter.
>
> Wow. Important saftey tip.

I posted this before, but you might find this relevant. 

    In Allegro, if you (declare (optimize (speed 1))) you should get
    tail recursion.  Alternatively you can just turn it on like this:

    (setq compiler:tail-call-self-merge�switch t) 
    (setq compiler:tail-call-non-self-merge-switch t) 


    In Lispworks, (declare (optimize (debug 2))) should do it. 
    Alternatively, this just turns it on unconditionally everywhere in
    lispworks: 


    (setq compiler::*debug-do-tail-merge-policy*      'true 
          compiler::*eliminate-tail-recursion-policy* 'true) 


    (compiler::update-policy-switches)

> Now I have to do some thinking about where all I've been using tail
> recursion.

I do this so I don't have to bother thinking about whether I've been
using tail recursion at all.

~jrm
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.25.15.41.06.395182@cunningham.net>
On Thu, 25 Aug 2005 11:31:40 -0400, Joe Marshall wrote:

> Jeff Cunningham <·······@cunningham.net> writes:
> 
>> On Thu, 25 Aug 2005 03:28:04 +0000, Peter Seibel wrote:
>>>
>>> Sure. Though keep in mind that Common Lisp implementations are not
>>> required to compile tail calls so they take finite stack so your
>>> version could use as many stack frames as half the length of
>>> NEWPROPS. Which probably doesn't matter.
>>
>> Wow. Important saftey tip.
> 
> I posted this before, but you might find this relevant. 
> 
>     In Allegro, if you (declare (optimize (speed 1))) you should get
>     tail recursion.  Alternatively you can just turn it on like this:
> 
>     (setq compiler:tail-call-self-merge�switch t) 
>     (setq compiler:tail-call-non-self-merge-switch t) 
> 
> 
>     In Lispworks, (declare (optimize (debug 2))) should do it. 
>     Alternatively, this just turns it on unconditionally everywhere in
>     lispworks: 
> 
> 
>     (setq compiler::*debug-do-tail-merge-policy*      'true 
>           compiler::*eliminate-tail-recursion-policy* 'true) 
> 
> 
>     (compiler::update-policy-switches)
> 
>> Now I have to do some thinking about where all I've been using tail
>> recursion.
> 
> I do this so I don't have to bother thinking about whether I've been
> using tail recursion at all.
> 
> ~jrm

If I understand what you are saying, you are turning "on" tail recursion
by these optimization settings? Doesn't that increase the risk of a stack
overflow as Peter was saying?

I'm using CMUCL and according to their documentation, tail recursion
seems to be on all the time unless you specifically turn it off via
debug settings. 

I had been using tail recursion wherever possible for the speed, unaware
of the stack limits. 

-Jeff
From: Duane Rettig
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <4ll2qj5zo.fsf@franz.com>
Jeff Cunningham <·······@cunningham.net> writes:

> On Thu, 25 Aug 2005 11:31:40 -0400, Joe Marshall wrote:
>
>> Jeff Cunningham <·······@cunningham.net> writes:
>> 
>>> On Thu, 25 Aug 2005 03:28:04 +0000, Peter Seibel wrote:
>>>>
>>>> Sure. Though keep in mind that Common Lisp implementations are not
>>>> required to compile tail calls so they take finite stack so your
>>>> version could use as many stack frames as half the length of
>>>> NEWPROPS. Which probably doesn't matter.
>>>
>>> Wow. Important saftey tip.
>> 
>> I posted this before, but you might find this relevant. 
>> 
>>     In Allegro, if you (declare (optimize (speed 1))) you should get
>>     tail recursion.  Alternatively you can just turn it on like this:
>> 
>>     (setq compiler:tail-call-self-merge�switch t) 
>>     (setq compiler:tail-call-non-self-merge-switch t) 
>> 
>> 
>>     In Lispworks, (declare (optimize (debug 2))) should do it. 
>>     Alternatively, this just turns it on unconditionally everywhere in
>>     lispworks: 
>> 
>> 
>>     (setq compiler::*debug-do-tail-merge-policy*      'true 
>>           compiler::*eliminate-tail-recursion-policy* 'true) 
>> 
>> 
>>     (compiler::update-policy-switches)
>> 
>>> Now I have to do some thinking about where all I've been using tail
>>> recursion.
====^^^^^^^^^

>> I do this so I don't have to bother thinking about whether I've been
>> using tail recursion at all.
>> 
>> ~jrm

Please be careful in your terminology.  Others who are posting are
doing so, and you should also do so.  Perhaps you understand tail
recursion and tail "merging" and are simply being lazy in your
use of the term, but it may also be due to a fundamental misunderstanding
about what tail recursion is.  Tail recursion is not a compiler
optimization, nor is it a method of compiling; it is a program
configuration:

(defun foo (x)
   (if (bar x)
       (foo (1- x))
     (1- (foo x))))

The first call to foo within foo is tail-recusrive.  Period.  It is
in the tail position, and the return value from the inner call is
precisely what is returned from the outer call.

The second call to foo is not tail recursive.  Period.  It is recursive,
but it is not in tail position.

The first call can be "optimized" for stack space (though it doesn't
necessarily generate faster code, so it's not necessarily being optimized
for time) by reusing the stack from the outer call to foo.

> If I understand what you are saying, you are turning "on" tail recursion
> by these optimization settings?

I am going to assume you mean "tail merging", which is the term we use
in Allegro CL for the changed handling of the compilation to optimize
for stack space.

> Doesn't that increase the risk of a stack overflow as Peter was saying?

Yes.  It also increases the risk of being more debuggable.

> I'm using CMUCL and according to their documentation, tail recursion
> seems to be on all the time unless you specifically turn it off via
> debug settings. 

Don't know about this.  Our tail-...-switch variables have functions
named for the kind of value they return, and one is dependent on the
value of the debug quality.

> I had been using tail recursion wherever possible for the speed, unaware
> of the stack limits. 

[Assuming "tail recursion" -> "tail merging"]:
This is the wrong motiviation for tail-merging.  You will sometimes
get speedups, but you will also sometimes get slower code.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.26.00.34.34.949187@cunningham.net>
On Thu, 25 Aug 2005 10:12:11 -0700, Duane Rettig wrote:

> 
> [Assuming "tail recursion" -> "tail merging"]:
> This is the wrong motiviation for tail-merging.  You will sometimes
> get speedups, but you will also sometimes get slower code.

So what criterion do you use when deciding how to write a recursion? Is it
purely for clarity? Or are there performance reasons you can rely upon?

-jeff
From: Rob Warnock
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <RrKdnai44olUD5PeRVn-oQ@speakeasy.net>
Jeff Cunningham  <·······@cunningham.net> wrote:
+---------------
| Duane Rettig wrote:
| > [Assuming "tail recursion" -> "tail merging"]:
| > This is the wrong motiviation for tail-merging.  You will sometimes
| > get speedups, but you will also sometimes get slower code.
| 
| So what criterion do you use when deciding how to write a recursion?
| Is it purely for clarity? Or are there performance reasons you can
| rely upon? 
+---------------

You write recursive algorithms when the data you're traversing or
the algorithm you're performing are expressed naturally in a
recursive fashion, e.g., walking a tree or graph.

You write iterative algorithms when the data you're traversing or
the algorithm you're performing are expressed naturally in a
iterative fashion, e.g., counting, summing, searching arrays,
successive approximation, etc.

OCCASIONALLY you may want [for simplicity] or need [to avoid stack
explosion] to write an iterative algorithm for a "naturally recursive"
problem or vice versa [e.g. a recursive paritition sort instead of
a linear insertion sort], but by & large it's generally best to stick
to the natural "shape" of the data or the mathematics at hand.


-Rob

p.s.  Even though it uses Scheme for its examples [and thus tends to
put much more weight on the recursive side], "How To Design Programs"
<http://www.htdp.org/> provides a good introduction to data- or problem-
directed software design, especially the sections on "design recipes"
<http://www.htdp.org/2003-09-26/Book/curriculum-Z-H-5.html#node_sec_2.5>
and <http://www.htdp.org/2003-09-26/Book/curriculum-Z-H-16.html#node_sec_12.1>
"designing complex programs".

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Joe Marshall
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <u0heq7s1.fsf@ccs.neu.edu>
Jeff Cunningham <·······@cunningham.net> writes:

> If I understand what you are saying, you are turning "on" tail recursion
> by these optimization settings? Doesn't that increase the risk of a stack
> overflow as Peter was saying?

I think we have different definitions of `on'.  With the settings I
gave, for the implementations in question, the compiler will attempt
to optimize tail calls when feasible.  This decreases the risk of
stack overflow because the optimized calls will be turned into jumps.

> I'm using CMUCL and according to their documentation, tail recursion
> seems to be on all the time unless you specifically turn it off via
> debug settings. 



> I had been using tail recursion wherever possible for the speed, unaware
> of the stack limits. 

Tail recursion isn't a speed optimization, it's a space optimization.
There may be an auxiliary speed effect because stack usage is more
localized, but the main benefit comes from space reduction.

~jrm
From: Thomas A. Russ
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <ymi1x4cfwmw.fsf@sevak.isi.edu>
Jeff Cunningham <·······@cunningham.net> writes:

> If I understand what you are saying, you are turning "on" tail recursion
> by these optimization settings? Doesn't that increase the risk of a stack
> overflow as Peter was saying?

What is being turned on is tail recursion optimization.  That REDUCES
the risk of stack overflow by converting the recursive calls into jumps
that do not consume additional stack space.  In effect it converts a
properly tail recursive function into (in effect) an iterative function.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.25.15.36.57.676311@cunningham.net>
Peter,

In fact, send in an order for a couple CDs to http://www.makewavs.com and
it will be on me.

I've written the generator for that site in CL making extensive use of
both your html and pathnames packages. The forms are still managed by
Perl, but I'm working on that too. All of the signal processing process
control is managed by CL scripts, as well as the library database, all
though all the hard-core audio signal processing is done in C. And I'm a
total Lisp noob.

-jeff
From: Peter Seibel
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <m2r7cgq7te.fsf@gigamonkeys.com>
Jeff Cunningham <·······@cunningham.net> writes:

> Peter,
>
> In fact, send in an order for a couple CDs to http://www.makewavs.com and
> it will be on me.

Hmmm. I'm not sure I have any vinyl left. (Wait, I think I have an old
LP of the Soviet National Anthem. Maybe I'll dig that out and send it
to you guys to rip.)

> I've written the generator for that site in CL making extensive use of
> both your html and pathnames packages. The forms are still managed by
> Perl, but I'm working on that too. All of the signal processing process
> control is managed by CL scripts, as well as the library database, all
> though all the hard-core audio signal processing is done in C. And I'm a
> total Lisp noob.

That is excellent news. I actually have a forms library that I wrote
that I need to integrate with the url-infrastrtucture code from my
book. Though I don't know if I'll get around to releasing that in time
to do you any good.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Pascal Bourguignon
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <873boz4gn6.fsf@thalassa.informatimago.com>
Jeff Cunningham <·······@cunningham.net> writes:
> I never think of flet. Good idea. Just out of curiousity, is there an
> advantage (like less machinery?). 

The scope where the bodies of the defined functions live is not the same.

[207]> (values
        (flet ((sin (x) (list (eq (function sin) (symbol-function 'sin))
                              (eq (function cos) (symbol-function 'cos))))
               (cos (x) (list (eq (function sin) (symbol-function 'sin))
                              (eq (function cos) (symbol-function 'cos)))))
          (list (sin 1) (cos 1)))

        (labels ((sin (x) (list (eq (function sin) (symbol-function 'sin))
                                (eq (function cos) (symbol-function 'cos))))
                 (cos (x) (list (eq (function sin) (symbol-function 'sin))
                                (eq (function cos) (symbol-function 'cos)))))
          (list (sin 1) (cos 1))))
((T T) (T T)) ;
((NIL NIL) (NIL NIL))

With FLET, all functions inside the bodies of the defined functions
refer to the functions visibles outisde of the flet.

With LABELS, all the functions defined in by the LABELS shadow the
functions outisde of the LABELS, in particular, forward and recursive
references are possible.

-- 
"This machine is a piece of GAGH!  I need dual Opteron 850
processors if I am to do battle with this code!"
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.25.02.12.15.38151@cunningham.net>
On Wed, 24 Aug 2005 15:18:53 +0200, Pascal Bourguignon wrote:

> Jeff Cunningham <·······@cunningham.net> writes:
>> I never think of flet. Good idea. Just out of curiousity, is there an
>> advantage (like less machinery?). 
> 
> The scope where the bodies of the defined functions live is not the same.
> 
> [207]> (values
>         (flet ((sin (x) (list (eq (function sin) (symbol-function 'sin))
>                               (eq (function cos) (symbol-function 'cos))))
>                (cos (x) (list (eq (function sin) (symbol-function 'sin))
>                               (eq (function cos) (symbol-function 'cos)))))
>           (list (sin 1) (cos 1)))
> 
>         (labels ((sin (x) (list (eq (function sin) (symbol-function 'sin))
>                                 (eq (function cos) (symbol-function 'cos))))
>                  (cos (x) (list (eq (function sin) (symbol-function 'sin))
>                                 (eq (function cos) (symbol-function 'cos)))))
>           (list (sin 1) (cos 1))))
> ((T T) (T T)) ;
> ((NIL NIL) (NIL NIL))
> 
> With FLET, all functions inside the bodies of the defined functions
> refer to the functions visibles outisde of the flet.
> 
> With LABELS, all the functions defined in by the LABELS shadow the
> functions outisde of the LABELS, in particular, forward and recursive
> references are possible.

Thank you for the explanation. That is a very useful difference.

-jeff
From: Peter Seibel
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <m2k6ictxiu.fsf@gigamonkeys.com>
Jeff Cunningham <·······@cunningham.net> writes:

> On Mon, 22 Aug 2005 17:19:03 +0000, Peter Seibel wrote:
>
>> Jeff Cunningham <·······@cunningham.net> writes:
>> 
>>> On Mon, 22 Aug 2005 05:51:05 +0000, Peter Seibel wrote:
>>>
>>>> 
>>>> Eh? Where ore those :prop2 and :prop3 values coming from. I don't
>>>> think you're doing what you think you're doing. Maybe show us the
>>>> actual REPL interaction.
>>>> 
>>>
>>> No doubt you are right. Here's the exact code:
>>>
>>> (defun update-props (proplist &key
>>>                     (prop1 nil prop1-set-p)
>>>                     (prop2 nil prop2-set-p)
>>>                     (prop3 nil prop3-set-p)
>>>                     (prop4 nil prop4-set-p)
>>>                     (prop5 nil prop5-set-p))
>>>   "Modifies designated properties of a list of property lists"
>>>   (labels ((update-term (prop)
>>>              (when prop1-set-p
>>>                (setf (getf prop :prop1) prop1))
>>>              (when prop2-set-p
>>>                (setf (getf prop :prop2) prop2))
>>>              (when prop3-set-p
>>>                (setf (getf prop :prop3) prop3))
>>>              (when prop4-set-p
>>>                (setf (getf prop :prop4) prop4))
>>>              (when prop5-set-p
>>>                (setf (getf prop :prop5) prop5))
>>>              prop))
>>>     (mapcar #'update-term proplist)))
>>>
>>> ;; According to P. Seibel, this is the same thing:
>>> (defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
>>>     (loop for (key value) on new-values by #'cddr do
>>>       (setf (getf plist key) value))
>>>     plist)
>>>
>>> ;; TEST:
>>> (defparameter *test* '((:prop1 T) (:prop1 "hi" :prop5 'bar)))
>>> (format t "~s~2%" (update-props *test* :prop1 nil :prop2 "abc" :prop3
>>> 'foo)) 
>>> (format t "~s~%" (update-properties *test* :prop1 nil :prop2 "abc"
>>> :prop3 'foo))
>> 
>> Okay, to *test*, as Wade pointed out is not a plist. I plist should
>> just be a list of alternating symbols and values. You can't use GETF
>> on *test* as it stands and get any kind of reasonable results.
>> 
>> -Peter
>
> I didn't mean to say *test* was a plist. Its a list of plists. That's
> why I'm using the mapcar to walk through it. The idea is that each plist
> has the update-props function applied to it in turn. Note my comment in
> the code:
>
>>   "Modifies designated properties of a list of property lists"

Ah, I was mislead by the variable names "proplist" and "prop". I might
name those "plists" and "plist" to make it clear that the former is a
list of plists and the latter is, in fact, a plist.

> So my question still stands: is there a simplier way to write the
> update-props function so it does what mine does - which is highly
> structured and repetitive. I'm pretty new to lisp and it seems like
> the kind of thing you should be able to reduce to a macro or
> something if you know more than I do. Your idea with the loop looks
> promising, but it doesn't behave properly yet.

I'm still not sure that I've grokked what you're trying to do but I
think this is more like it:

  (defun update-properties (list-of-plists &rest newprops &key prop1 prop2 prop3 prop4 prop5)
    (declare (ignore prop1 prop2 prop3 prop4 prop5))
    (loop for plist in list-of-plists collect
         (loop for (prop value) on newprops by #'cddr do 
              (setf (getf plist prop) value)
              finally (return plist))))

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Jeff Cunningham
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <pan.2005.08.24.02.19.53.168306@cunningham.net>
On Tue, 23 Aug 2005 16:42:50 +0000, Peter Seibel wrote:
> 
> Ah, I was mislead by the variable names "proplist" and "prop". I might
> name those "plists" and "plist" to make it clear that the former is a
> list of plists and the latter is, in fact, a plist.
 
Your names are certainly better than mine. A case of their meaning
changing as I was developing the code (they were once as I named them).


> I'm still not sure that I've grokked what you're trying to do but I
> think this is more like it:
> 
>   (defun update-properties (list-of-plists &rest newprops &key prop1 prop2 prop3 prop4 prop5)
>     (declare (ignore prop1 prop2 prop3 prop4 prop5))
>     (loop for plist in list-of-plists collect
>          (loop for (prop value) on newprops by #'cddr do 
>               (setf (getf plist prop) value)
>               finally (return plist))))
> 
> -Peter

You have it exactly. Now, I'm going to have to sit down with your book
(which I own) and figure out how it works. 

Much obliged.

--jeff
From: Andreas Thiele
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <dedf61$roe$04$1@news.t-online.com>
"Peter Seibel" <·····@gigamonkeys.com> schrieb im Newsbeitrag ···················@gigamonkeys.com...
> Jeff Cunningham <·······@cunningham.net> writes:
>
> > On Mon, 22 Aug 2005 05:51:05 +0000, Peter Seibel wrote:
> >
> >>
> >> Eh? Where ore those :prop2 and :prop3 values coming from. I don't
> >> think you're doing what you think you're doing. Maybe show us the
> >> actual REPL interaction.
> >>
> >
> > No doubt you are right. Here's the exact code:
> >
> > (defun update-props (proplist &key
> >                     (prop1 nil prop1-set-p)
> >                     (prop2 nil prop2-set-p)
> >                     (prop3 nil prop3-set-p)
> >                     (prop4 nil prop4-set-p)
> >                     (prop5 nil prop5-set-p))
> >   "Modifies designated properties of a list of property lists"
> >   (labels ((update-term (prop)
> >              (when prop1-set-p
> >                (setf (getf prop :prop1) prop1))
> >              (when prop2-set-p
> >                (setf (getf prop :prop2) prop2))
> >              (when prop3-set-p
> >                (setf (getf prop :prop3) prop3))
> >              (when prop4-set-p
> >                (setf (getf prop :prop4) prop4))
> >              (when prop5-set-p
> >                (setf (getf prop :prop5) prop5))
> >              prop))
> >     (mapcar #'update-term proplist)))
> >
> > ;; According to P. Seibel, this is the same thing:
> > (defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
> >     (loop for (key value) on new-values by #'cddr do
> >       (setf (getf plist key) value))
> >     plist)
> >
> > ;; TEST:
> > (defparameter *test* '((:prop1 T) (:prop1 "hi" :prop5 'bar)))
> > (format t "~s~2%" (update-props *test* :prop1 nil :prop2 "abc" :prop3
> > 'foo))
> > (format t "~s~%" (update-properties *test* :prop1 nil :prop2 "abc"
> > :prop3 'foo))
>
> Okay, to *test*, as Wade pointed out is not a plist. I plist should
> just be a list of alternating symbols and values. You can't use GETF
> on *test* as it stands and get any kind of reasonable results.
>
> -Peter
>
> --
> Peter Seibel           * ·····@gigamonkeys.com
> Gigamonkeys Consulting * http://www.gigamonkeys.com/
> Practical Common Lisp  * http://www.gigamonkeys.com/book/

Your first post is somehow strange, because your lists have not been property list. Funny thing is,
(setf (getf malformed-plist :something) :some-value) is working, but certainly is no good practise.

The point between your version and Peters is, Peters version works on a single plist. So you'd have
to map #'update-properties across your list of plists (assumed from your second example).

Andreas
From: lin8080
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <430AFF54.11DC187B@freenet.de>
Peter Seibel schrieb:
> Jeff Cunningham <·······@cunningham.net> writes:

> > (defun update-props (proplist &key
> >                     (prop1 nil prop1-set-p)
> >                     (prop2 nil prop2-set-p)
> >                     (prop3 nil prop3-set-p)
> >                     (prop4 nil prop4-set-p)
> >                     (prop5 nil prop5-set-p))
> >   "Modifies designated properties of a list of property lists"
> >   (labels ((update-term (prop)
> >              (when prop1-set-p
> >                (setf (getf prop :prop1) prop1))
> >              (when prop2-set-p
> >                (setf (getf prop :prop2) prop2))
> >              (when prop3-set-p
> >                (setf (getf prop :prop3) prop3))
> >              (when prop4-set-p
> >                (setf (getf prop :prop4) prop4))
> >              (when prop5-set-p
> >                (setf (getf prop :prop5) prop5))
> >              prop))
> >     (mapcar #'update-term proplist)))

>   (defun update-properties (plist &rest new-values &key prop1 prop2 prop3 prop4 prop5)
>     (loop for (key value) on new-values by #'cddr do
>       (setf (getf plist key) value))
>     plist)

... reading Peter Seibel always makes me crazy. Thank you -on the fly.
From: Wade Humeniuk
Subject: Re: How can I make this function simplier?
Date: 
Message-ID: <TDkOe.152078$wr.638@clgrps12>
Jeff Cunningham wrote:
> The following function does what I want it to do: that is, it modifies
> selected properties of a list of property lists. Its seems like a lot of
> redundant typing. Is this a case where one should use a macro? Or is there
> another way to write this more compactly?
> 
> (defun update-props (proplist &key
>                     (prop1 nil prop1-set-p)
>                     (prop2 nil prop2-set-p)
>                     (prop3 nil prop3-set-p)
>                     (prop4 nil prop4-set-p)
>                     (prop5 nil prop5-set-p))
>   "Modifies designated properties of a list of property lists"
>   (labels ((update-term (prop)
>              (when prop1-set-p
>                (setf (getf prop :prop1) prop1))
>              (when prop2-set-p
>                (setf (getf prop :prop2) prop2))
>              (when prop3-set-p
>                (setf (getf prop :prop3) prop3))
>              (when prop4-set-p
>                (setf (getf prop :prop4) prop4))
>              (when prop5-set-p
>                (setf (getf prop :prop5) prop5))
>              prop))
>     (mapcar #'update-term proplist)))
> 
> ;; TEST:
> (defparameter *test* '(((:prop1 T) :prop1 "hi" :prop5 'bar)))
> (print (update-props *test* :prop1 nil :prop2 "abc" :prop3 'foo))
> 
> ;; ((:PROP3 FOO :PROP2 "abc" :PROP1 NIL (:PROP1 T) :PROP1 "hi" :PROP5 'BAR))
> 

First *test* is not a proper list of property lists.

Since you destructively modify *test* anyways,

(defun update-props (proplist &key
                     (prop1 nil prop1-set-p)
                     (prop2 nil prop2-set-p)
                     (prop3 nil prop3-set-p)
                     (prop4 nil prop4-set-p)
                     (prop5 nil prop5-set-p))
   "Modifies designated properties of a list of property lists"
   (dolist (prop proplist)
     (when prop1-set-p (setf (getf prop :prop1) prop1))
     (when prop2-set-p (setf (getf prop :prop2) prop2))
     (when prop3-set-p (setf (getf prop :prop3) prop3))
     (when prop4-set-p (setf (getf prop :prop4) prop4))
     (when prop5-set-p (setf (getf prop :prop5) prop5)))
   proplist)

Wade