I was wondering if it would be a good idea to have the function position
return multiple values with the position of the first element returning
non nil to a given function, and a second value with the value itself.
For example:
(position #'(lambda (n) (if (numberp n) (sqrt n))) '(a b 2 3))
==> 2 1.4142135
I find this quite useful, and made me wonder if there's any special
reason for not defining position like that, or if people use a different
function to do it.
Any one knows the answer?
Marisa <······@kabelfoon.nl> writes:
> I was wondering if it would be a good idea to have the function position
> return multiple values with the position of the first element returning
> non nil to a given function, and a second value with the value itself.
> For example:
> (position #'(lambda (n) (if (numberp n) (sqrt n))) '(a b 2 3))
> ==> 2 1.4142135
>
> I find this quite useful, and made me wonder if there's any special
> reason for not defining position like that, or if people use a different
> function to do it.
> Any one knows the answer?
I assume you mean POSITION-IF, not POSITION.
It means shifting all the values. Just a hassle, and maybe not used that
much. Mostly it's not a computation but an access, and repeating the
access is barely more time than setting up the multiple-value receipt
"just in case". Remember that you're slowing down POSITION-IF in the simple
case that the person really does just want one value unless the compiler
can detect the need for just one value and secretly call a different
function which does what POSITION-IF is now defined to do.
Mostly for your case, you'll find that
(loop for index from 0
for n in seq ; assumes seq is a list
for primary = (if (numberp n) (sqrt n))
when primary
return (values index primary))
will suffice to do the simple thing in the rare case it's needed, so it's
not like a new function buys that much. But consider that to really handle
multiple values right, you'd want to do:
(defmethod multiple-value-position-if (fn (seq vector))
(loop for index from 0
for elt = (char seq index) ;assumes seq is a vector
do (flet ((test (&rest values)
(declare (dynamic-extent values))
(when (first values)
(return-from multiple-value-position
(apply #'values index values)))))
(declare (dynamic-extent #'test))
(multiple-value-call #'test (funcall fn elt)))))
(defmethod multiple-value-position-if (fn (seq list))
(loop for index from 0
for elt in seq
do (flet ((test (&rest values)
(declare (dynamic-extent values))
(when (first values)
(return-from multiple-value-position
(apply #'values index values)))))
(declare (dynamic-extent #'test))
(multiple-value-call #'test (funcall fn elt)))))
If you're LUCKY, this won't cons because it keep using downward
objects and declaring them dynamic-extent. Depends on the
implementation, though. But even when you're lucky, it will do a lot
more work than the loop above because it cannot anticipate the number
of values to expect. So it's another one of those trade-offs that I
keep saying pepper the world of choices from which CL was carved.