[alexandria-devel] Implementation of DELETE-FROM-PLIST

Stas Boukarev stassats at gmail.com
Sat Feb 23 16:08:55 UTC 2013


Robert Smith <quad at symbo1ics.com> writes:

> Hey:
>
> Here's a destructive/non-consing version of DELETE-FROM-PLIST. I've
> tested with (I think) all corner cases from the REPL, but I ought to
> write tests proper.
>
> The function is here http://tinyurl.com/adqkssu ;or the following huge
> link, in case the last one is invalidated
> https://bitbucket.org/tarballs_are_good/lisp-random/src/3db634111d35e788c6ea2f4a1b3ab38334e24cde/miscellaneous_exercises/delete-from-plist.lisp?at=default#cl-30
> .
>
> For simplicity or ease of review from an email client, I've pasted the
> function at the end of this email.
>
> Additionally, this function would make it pretty easy to write
> DELETE-FROM-PLIST-IF{-NOT}, since the function to determine if a key
> is bad is factored out. If one did write this function, then it would
> be easy to define DELETE-FROM-PLIST in terms of it.
>
> Let me know if there are any changes that should be made.
>
> Cheers,
>
> Robert Smith
>
>
> ;;;; from delete-from-plist.lisp
>
> (defun delete-from-plist (plist &rest keys)
>   "Delete all keys and pairs indicated by KEYS from the plist PLIST."
>   (labels ((assert-proper-plist (x)
>              (assert x () "Expected a proper plist, got ~S" plist))
>            (bad-key-p (key)
>              (member key keys :test #'eq))
>            (find-first ()
>              "Find the first cons in PLIST to keep."
>              (loop :for the-cons :on plist :by #'cddr
>                    :unless (prog1 (bad-key-p (car the-cons))
>                              (assert-proper-plist (cdr the-cons)))
>                      :do (return the-cons)
>                    :finally (return nil))))
>     (declare (inline assert-proper-plist
>                      bad-key-p
>                      find-first))
>     ;; Find the first good key and delete any bad key-value pairs
>     ;; between it and the start.
>     (let ((first (find-first)))
>       (unless (eq first plist)
>         (setf (cddr plist)
>               first))
>
>       ;; At this point, we know FIRST points to the first key
>       ;; which exists, or NIL.
>       (loop :with last-good := first    ; Keep the last good key
>             :for the-cons :on (cddr first) :by #'cddr
>             :do (progn
>                   (assert-proper-plist (cdr the-cons))
>                   (if (bad-key-p (car the-cons))
>                       (setf (cddr last-good)
>                             (cddr the-cons))
>                       (setf last-good the-cons)))
>             :finally (return first)))))
>
Alexandria is not using :keyword style for LOOP.
DO in loop has an implicit progn, no need for an explicit one.
unless (prog1 ... (assert)) can be better expressed as
do (assert)
unless ... return cons
and finally (return nil) is not needed.

And I don't quite understand the purpose of
(unless (eq first plist)
        (setf (cddr plist)
              first))
-- 
With best regards, Stas.




More information about the alexandria-devel mailing list