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

2014-03-03 Thread Attila Lendvai
pushed, thanks!

and sorry for the delay!

-- 
• attila lendvai
• PGP: 963F 5D5F 45C7 DFCD 0A39
--
“It ain’t what you don’t know that gets you in trouble. It’s what you
know for sure that ain’t so.”
— Mark Twain (1835–1910)



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

2013-02-26 Thread James M. Lawrence
Apologies to Robert for stealing his thunder.


0001-make-REMOVE-FROM-PLIST-non-consing.patch
Description: Binary data


0002-fix-test-PARSE-ORDINARY-LAMBDA-LIST.1.patch
Description: Binary data
___
alexandria-devel mailing list
alexandria-devel@common-lisp.net
http://lists.common-lisp.net/cgi-bin/mailman/listinfo/alexandria-devel


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

2013-02-24 Thread Zach Beane
James M. Lawrence llmjj...@gmail.com writes:

 Using two loops seems awkward to me. How about one?

 (defun delete-from-plist (plist rest keys)
   (loop with head = plist
 with tail = nil
 for (key . rest) on plist by #'cddr
 do (assert rest () Expected a proper plist, got ~S plist)
(if (member key keys :test #'eq)
(let ((next (cdr rest)))
  (if tail
  (setf (cdr tail) next)
  (setf head next)))
(setf tail rest))
 finally (return head)))

I mention this for completeness and novelty, not for suitability:

  (defun sans (plist rest keys)
(let ((sans ()))
  (loop
(let ((tail (nth-value 2 (get-properties plist keys
  ;; this is how it ends
  (unless tail
(return (nreconc sans plist)))
  ;; copy all the unmatched keys
  (loop until (eq plist tail) do
(push (pop plist) sans)
(push (pop plist) sans))
  ;; skip the matched key
  (setq plist (cddr plist))

I don't think I've seen GET-PROPERTIES and NRECONC outside this
function.

I got it from here:
http://xach.com/naggum/articles/3247672165664225%40naggum.no.html

Zach

___
alexandria-devel mailing list
alexandria-devel@common-lisp.net
http://lists.common-lisp.net/cgi-bin/mailman/listinfo/alexandria-devel


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

2013-02-24 Thread Stas Boukarev
Zach Beane x...@xach.com writes:

 James M. Lawrence llmjj...@gmail.com writes:

 Using two loops seems awkward to me. How about one?

 (defun delete-from-plist (plist rest keys)
   (loop with head = plist
 with tail = nil
 for (key . rest) on plist by #'cddr
 do (assert rest () Expected a proper plist, got ~S plist)
(if (member key keys :test #'eq)
(let ((next (cdr rest)))
  (if tail
  (setf (cdr tail) next)
  (setf head next)))
(setf tail rest))
 finally (return head)))

 I mention this for completeness and novelty, not for suitability:

   (defun sans (plist rest keys)
 (let ((sans ()))
   (loop
 (let ((tail (nth-value 2 (get-properties plist keys
   ;; this is how it ends
   (unless tail
 (return (nreconc sans plist)))
   ;; copy all the unmatched keys
   (loop until (eq plist tail) do
 (push (pop plist) sans)
 (push (pop plist) sans))
   ;; skip the matched key
   (setq plist (cddr plist))

 I don't think I've seen GET-PROPERTIES and NRECONC outside this
 function.

 I got it from here:
 http://xach.com/naggum/articles/3247672165664225%40naggum.no.html
If striving for shortness:

(defun delete-from-plist (plist rest keys)
  (dolist (key keys plist)
(remf plist key)))

-- 
With best regards, Stas.

___
alexandria-devel mailing list
alexandria-devel@common-lisp.net
http://lists.common-lisp.net/cgi-bin/mailman/listinfo/alexandria-devel


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

2013-02-24 Thread Robert Smith
Looks good! Much cleaner/better.

-Robert

On Sun, Feb 24, 2013 at 6:30 AM, James M. Lawrence llmjj...@gmail.com wrote:
 On Sat, Feb 23, 2013 at 4:09 AM, Robert Smith q...@symbo1ics.com wrote:

 (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)

 Using two loops seems awkward to me. How about one?

 (defun delete-from-plist (plist rest keys)
   (loop with head = plist
 with tail = nil
 for (key . rest) on plist by #'cddr
 do (assert rest () Expected a proper plist, got ~S plist)
(if (member key keys :test #'eq)
(let ((next (cdr rest)))
  (if tail
  (setf (cdr tail) next)
  (setf head next)))
(setf tail rest))
 finally (return head)))

 ___
 alexandria-devel mailing list
 alexandria-devel@common-lisp.net
 http://lists.common-lisp.net/cgi-bin/mailman/listinfo/alexandria-devel

___
alexandria-devel mailing list
alexandria-devel@common-lisp.net
http://lists.common-lisp.net/cgi-bin/mailman/listinfo/alexandria-devel


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

2013-02-23 Thread Robert Smith
How is (:A 1 :D 4) wrong? There is no way to get it to just (:D 4) via
mutation when passing to a function. If we want to have just (:D 4),
we will need to either pass in

(nil nil plist)

which will give

(nil nil :D 4)

or we will need to encapsulate or box the value before going in, by
using something like https://bitbucket.org/tarballs_are_good/cl-ref .

All in all, it still returns (:D 4), but it just modifies as much of
the list structure as it can.

-Robert

On Sat, Feb 23, 2013 at 11:53 AM, Stas Boukarev stass...@gmail.com wrote:
 Robert Smith q...@symbo1ics.com writes:

 Good style remarks, I suppose, which I can change.

 On Sat, Feb 23, 2013 at 8:08 AM, Stas Boukarev stass...@gmail.com wrote:
 And I don't quite understand the purpose of
 (unless (eq first plist)
 (setf (cddr plist)
   first))

 The point of that was for more DWIMness.

 Without it, we have:

 CL-USER (let ((x (list :a 1 :b 2 :c 3 :d 4)))
(print (delete-from-plist x :a :b :c))
x)

 (:D 4)
 (:A 1 :B 2 :C 3 :D 4)

 And with it, we have:

 CL-USER (let ((x (list :a 1 :b 2 :c 3 :d 4)))
(print (delete-from-plist x :a :b :c))
x)

 (:D 4)
 (:A 1 :D 4)

 If your typical mode of operation is to (setf x (delete-from...)),
 then of course either are fine. If your goal is to use
 DELETE-FROM-PLIST for its side effects, then I think the latter is
 more useful. In fact, for really simple and efficient imperative
 maintenance of a plist, just prepend (nil nil), and use the function
 purely for mutation.
 I don't see how (:A 1 :D 4) is useful, it's less wrong, but it's still
 wrong.

 --
 With best regards, Stas.

___
alexandria-devel mailing list
alexandria-devel@common-lisp.net
http://lists.common-lisp.net/cgi-bin/mailman/listinfo/alexandria-devel


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

2013-02-23 Thread Robert Smith
On Sat, Feb 23, 2013 at 4:19 PM, Stas Boukarev stass...@gmail.com wrote:
 It's wrong because it's completely useless, why would anyone use
 delete-from-plist without using the value returned by it, if the
 original list it modifies has the wrong result? Having to prepend two
 NILs is just bogus.

1. Because some people like or prefer to modify data structures
(especially when you have elaborate data structures), and not
bindings.

2. Having to prepend two NILs is fine I think. Yes it is hacky, but I
don't see any inherent issue with it. It just establishes a (few)
conses that act as the head or entry point to the list.

 Although, that's not true that there's no way to have (:D 4), but the
 problem just shifts to when it deletes everything and it's a NIL:

 (unless (eq first plist)
   (psetf (car plist) (car first)
  (cdr plist) (cdr first)))

I suppose you're correct here. I was implicitly assuming that we would
want to never modify the CAR, but that is a sort of useless
assumption.

 But that part shouldn't be in alexandria (or any sane library, for that
 matter) either way, because it encourages erroneous usage, seemingly
 doing the right thing, but breaks when it comes to returning NIL.

I don't think it's erroneous. We aren't conflating the ideas of
modifying a data structure and modifying a binding. By not doing that
extra mutation, we rely on the user to finish the job by re-setting
their variable to the new value.

The only thing weird about it is that there are a lot of Lisp
functions which don't completely mutate the data structure, and
expect the user to modify the binding. As far as I can tell, then, the
really only argument against such a thing is that's not how other CL
functions work, so for consistency's sake, we shouldn't either.
Unless I'm missing some point.

 And there's alexandria:delete-from-plistf for people who are afraid of
 an extra SETF.

In this, we are trading a purely functional (i.e., non-special/macro)
solution for a macro solution. Doesn't that go against the grain of
the prevalent ideology of Lisp?

Cheers,

Robert

___
alexandria-devel mailing list
alexandria-devel@common-lisp.net
http://lists.common-lisp.net/cgi-bin/mailman/listinfo/alexandria-devel


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

2013-02-23 Thread Stas Boukarev
Robert Smith q...@symbo1ics.com writes:

 On Sat, Feb 23, 2013 at 4:19 PM, Stas Boukarev stass...@gmail.com wrote:
 It's wrong because it's completely useless, why would anyone use
 delete-from-plist without using the value returned by it, if the
 original list it modifies has the wrong result? Having to prepend two
 NILs is just bogus.

 1. Because some people like or prefer to modify data structures
 (especially when you have elaborate data structures), and not
 bindings.
Well, those people should learn that it's not possible in
general. Particularly with lists, because of NIL.

 2. Having to prepend two NILs is fine I think. Yes it is hacky, but I
 don't see any inherent issue with it. It just establishes a (few)
 conses that act as the head or entry point to the list.
What if the key you want to remove is NIL?

 But that part shouldn't be in alexandria (or any sane library, for that
 matter) either way, because it encourages erroneous usage, seemingly
 doing the right thing, but breaks when it comes to returning NIL.

 I don't think it's erroneous. We aren't conflating the ideas of
 modifying a data structure and modifying a binding. By not doing that
 extra mutation, we rely on the user to finish the job by re-setting
 their variable to the new value.
There's no other way to obtain the correct results otherwise. Having it
to work in 99% is worse than having it not to work at all, because
people might forget about the remaining 1% case more easily. So you end
up with doing extra work which has no use. The goal is simplicity, not
having to memorize in which cases it's alright and which it's not. Just
use the return value and be merry.

 And there's alexandria:delete-from-plistf for people who are afraid of
 an extra SETF.

 In this, we are trading a purely functional (i.e., non-special/macro)
 solution for a macro solution. Doesn't that go against the grain of
 the prevalent ideology of Lisp?
There's no trading, delete-from-plistf is just a define-modify-macro for
delete-from-plist.

-- 
With best regards, Stas.

___
alexandria-devel mailing list
alexandria-devel@common-lisp.net
http://lists.common-lisp.net/cgi-bin/mailman/listinfo/alexandria-devel