I define a dummy variable:
(setq dummy (list :expire (list :idle 3
:wait 1438)
:get-news (list :idle 2
:wait 29)))
But when executing the following statement:
(format t "~a~%" (set-property-in-list dummy 'testing (list :expire :idle)))
I get:
before-loop EXPIRE -> (EXPIRE (IDLE 3 WAIT 1438) GET-NEWS (IDLE 2 WAIT 29))
before-last (IDLE) -> (IDLE 3 WAIT 1438)
Tried to change a non-existing property
When executing:
(format t "~a~%" (set-property-in-list dummy 'testing (list :expire :idle :dummy)))
I get (beside an error of course):
before-loop EXPIRE -> (EXPIRE (IDLE 3 WAIT 1438) GET-NEWS (IDLE 2 WAIT 29))
before-loop IDLE -> (IDLE 3 WAIT 1438)
before-last (DUMMY) -> 3
Why does
(setq sub-list (getf sub-list current-property)))
work with IDLE on (IDLE 3 WAIT 1438), but
(setq property-value (getf sub-list this-property))
not?
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
> I do not have all the tips from here implemented yet, (learning CL,
> getting SLIME to work -very hand-, ...) but I have been trying to make
> set-property-in-list more general. First it worked with exactly two
> layers, but of course it would be better if it worked with any number of
> properties.
And why limit yourself to property lists?
There are general accessors such as:
http://groups.google.com/group/comp.lang.lisp/msg/1bab4b5bae1fdca3?dmode=source
Well, let's extend it for a-lists and p-lists:
(defun length<= (length list)
(or (zerop length) (and list (length<= (1- length) (cdr list)))))
(defun -> (object &rest path)
(cond
((null path) object)
((arrayp object)
(let ((d (array-rank object)))
(if (length<= d path)
(apply (function ->)
(apply (function aref) object (subseq path 0 d))
(nthcdr d path))
(make-array ; let's get a slice
(nthcdr (length path) (array-dimensions object))
:displaced-to object
:displaced-index-offset
(apply (function array-row-major-index) object
(append path (make-list (- d (length path))
:initial-element 0)))
:element-type (array-element-type object)))))
((and (listp object)
(every (function consp) object)
(not (integerp (first path))))
(apply (function ->) (cdr (assoc (first path) object)) (rest path)))
((listp object)
(apply (function ->)
(cond
((integerp (first path))
(elt object (first path)))
((every (function consp) object)
(cdr (assoc object (first path))))
((and (symbolp (first path))
(evenp (length object))
(loop :for (k nil) :on object :by (function cddr)
:always (symbolp k)))
(getf object (first path)))
((functionp (first path))
(funcall (first path) object))
(t (error "Unexpected index ~S for ~S" (first path) object)))
(rest path)))
((hash-table-p object)
(apply (function ->) (gethash (first path) object) (rest path)))
((typep object '(or structure-object standard-object))
(apply (function ->) (funcall (first path) object) (rest path)))
((or (functionp (first path))
(and (symbolp (first path)) (fboundp (first path))))
(apply (function ->) (funcall (first path) object) (rest path)))
(t
(error "This is not a compound object: ~S" object))))
(-> '(a #(1 ((:x . "abc") (:y . "def")) 11)
b #(2 ((:xx . "ghi") (:yy . "jkl")) 22)
c #(3 ((:xxx . "mno") (:yyy . "pqr")) 33))
'b 1 :yy 1) --> #\k
--
__Pascal Bourguignon__ http://www.informatimago.com/
I found the problem. When using last to retrieve the last element of a
list, the last element is returned as a list not as the value it is. So
I needed to change:
> (defun set-property-in-list(this-list value property-list)
> (let ((property-value)
> (sub-list this-list)
> (this-property (last property-list))
> (working-list (butlast property-list)))
> (dolist (current-property working-list)
> (format t "before-loop ~a -> ~a~%" current-property sub-list)
> (setq sub-list (getf sub-list current-property)))
> (format t "before-last ~a -> ~a~%" this-property sub-list)
> (setq property-value (getf sub-list this-property))
> (if (not property-value)
> (format nil "Tried to change a non-existing property")
> (progn
> (format t "~a~%" property-value)
> (setf (getf sub-list this-property) value)
> nil))))
into:
(defun set-property-in-list(this-list value property-list)
(let ((sub-list this-list)
(this-property (car (last property-list)))
(working-list (butlast property-list)))
(dolist (current-property working-list)
(setq sub-list (getf sub-list current-property)))
(if (and (listp sub-list)
(getf sub-list this-property))
(progn
(setf (getf sub-list this-property) value)
nil)
(format nil "Tried to change a non-existing property"))))
Now it does what it should (as far as I now) and is a little bit more robust.
>> I do not have all the tips from here implemented yet, (learning CL,
>> getting SLIME to work -very hand-, ...) but I have been trying to make
>> set-property-in-list more general. First it worked with exactly two
>> layers, but of course it would be better if it worked with any number of
>> properties.
>
> And why limit yourself to property lists?
Because I am still learning the language. ;-)
> There are general accessors such as:
> http://groups.google.com/group/comp.lang.lisp/msg/1bab4b5bae1fdca3?dmode=source
>
> Well, let's extend it for a-lists and p-lists:
That is something I have to study.
> Cecil Westerhof <Ce...@decebal.nl> writes:
>
> I found the problem. When using last to retrieve the last element of a
> list, the last element is returned as a list not as the value it is. So
I ran into that so often that I have written a last*, which is
equivalent to (car (last ...)) but implemented directly. Since you
are learning CL, I won't spoil the pleasure of writing it for you by
pasting it in (but feel free to ask).
Tamas
Graham's On Lisp has names it `last1' (name ends with decimal one) in
his chapter on utilities.
Mirko
>> I found the problem. When using last to retrieve the last element of a
>> list, the last element is returned as a list not as the value it is. So
>
> I ran into that so often that I have written a last*, which is
> equivalent to (car (last ...)) but implemented directly. Since you
> are learning CL, I won't spoil the pleasure of writing it for you by
> pasting it in (but feel free to ask).
The function is of course:
(defun last* (this-list)
(car (last this-list)))
But what do you mean by implemented directly?
Also I have seen several times that a function name ends with an
asterisk. Does this have a special meaning?
> Tamas K Papp <tkp...@gmail.com> writes:
>
>>> I found the problem. When using last to retrieve the last element of a
>>> list, the last element is returned as a list not as the value it is.
>>> So
>>
>> I ran into that so often that I have written a last*, which is
>> equivalent to (car (last ...)) but implemented directly. Since you are
>> learning CL, I won't spoil the pleasure of writing it for you by
>> pasting it in (but feel free to ask).
>
> The function is of course:
> (defun last* (this-list)
> (car (last this-list)))
>
> But what do you mean by implemented directly?
Make the function walk the list until cdr is nil, then return car.
You can do it with loop, tagbody, and probably other ways. Just say
the word, and people here will post 20+ ingenious solutions :-)
> Also I have seen several times that a function name ends with an
> asterisk. Does this have a special meaning?
Nope. It is just lack of creativity :-) Graham's last1 naming
convention, mentioned by Mirko, is probably nicer, "last one" is a
good mnemonic.
Tamas
>> The function is of course:
>> (defun last* (this-list)
>> (car (last this-list)))
>>
>> But what do you mean by implemented directly?
>
> Make the function walk the list until cdr is nil, then return car.
> You can do it with loop, tagbody, and probably other ways. Just say
> the word, and people here will post 20+ ingenious solutions :-)
Does that has any advantage above the above function?
>> Also I have seen several times that a function name ends with an
>> asterisk. Does this have a special meaning?
>
> Nope. It is just lack of creativity :-) Graham's last1 naming
> convention, mentioned by Mirko, is probably nicer, "last one" is a
> good mnemonic.
I think I rename it. :-D
> Tamas K Papp <tkp...@gmail.com> writes:
>
>>> The function is of course:
>>> (defun last* (this-list)
>>> (car (last this-list)))
>>>
>>> But what do you mean by implemented directly?
>>
>> Make the function walk the list until cdr is nil, then return car.
>> You can do it with loop, tagbody, and probably other ways. Just say
>> the word, and people here will post 20+ ingenious solutions :-)
>
> Does that has any advantage above the above function?
Almost none. In some implementation it might be faster to
re-implement it that way, to avoid a function call to last. But all
CL implementations are specifically allowed to open code all CL
functions, and on some implementations, calling a CL function would be
much much much much faster than re-implementing that code in lisp. So
any advantage is totally dubious on one hand, and totally bound to a
gain of about 1 ns on the other hand. Ludicruous!
> Cecil Westerhof <Ce...@decebal.nl> writes:
>
>> Tamas K Papp <tkp...@gmail.com> writes:
>>
>>>> The function is of course:
>>>> (defun last* (this-list)
>>>> (car (last this-list)))
>>>>
>>>> But what do you mean by implemented directly?
>>>
>>> Make the function walk the list until cdr is nil, then return car.
>>> You can do it with loop, tagbody, and probably other ways. Just say
>>> the word, and people here will post 20+ ingenious solutions :-)
>>
>> Does that has any advantage above the above function?
>
> Almost none. In some implementation it might be faster to
> re-implement it that way, to avoid a function call to last. But all
I thought that. So I am satisfied with my function.
> CL implementations are specifically allowed to open code all CL
> functions,
What does this mean?
> p...@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Cecil Westerhof <Ce...@decebal.nl> writes:
>>
>>> Tamas K Papp <tkp...@gmail.com> writes:
>>>
>>>>> The function is of course:
>>>>> (defun last* (this-list)
>>>>> (car (last this-list)))
>>>>>
>>>>> But what do you mean by implemented directly?
>>>>
>>>> Make the function walk the list until cdr is nil, then return car.
>>>> You can do it with loop, tagbody, and probably other ways. Just say
>>>> the word, and people here will post 20+ ingenious solutions :-)
>>>
>>> Does that has any advantage above the above function?
>>
>> Almost none. In some implementation it might be faster to
>> re-implement it that way, to avoid a function call to last. But all
>
> I thought that. So I am satisfied with my function.
>
>
>> CL implementations are specifically allowed to open code all CL
>> functions,
>
> What does this mean?
It means to inline more or less. That is, to generate code in the
calling functions, that would have to be modified if the called
function was modified, but since this is not something that a
conformant program may do for CL functions, conforming CL
implementations are allowed to do it.
Not formally. Suffixing a function or macro name with "*" is just
a common convention for a local/private extension to a standard
function, similar to prefixing a name with "my-" [e.g., MY-LAST].
E.g., I have a LOAD* which is like LOAD except it (1) takes a list
of pathnames, (2) adds them to a list of pathnames to be LOADed,
and (3) remembers each file's modification time and suppresses
the LOADing is the file hasn't changes since the last LOAD*.
[Think of it as a poor man's ASDF.] Or an EVAL-WHEN* macro that
automatically supplies all three conditions to EVAL-WHEN. Or a
COMPILE* macro that wraps the argument form in a LAMBDA, COMPILEs
it, then finally FUNCALLs the result. Or a MAKE-LIST* that can
build circular lists and can initialize elements to a function
of their position.
Or John Foderaro's IF* macro, which comes with Franz's Allegro Common Lisp.
Or even ANSI CL's DO*, LET*, LIST*, PROG*, each of which is a slight
tweak on on the functionality of the base name.
-Rob
-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Correct. To see what is going on, try the following and compare the results.
(last '(a b c))
(third '(a b c))
(Hint: LAST doesn't do what you expect).
If you need more items to try try the following:
(getf '(:idle 3 :wait 1438) :idle)
(getf '(:idle 3 :wait 1438) '(:idle))
--
Thomas A. Russ, USC/Information Sciences Institute