From: Marisa
Subject: A multiple valued position?
Date: 
Message-ID: <347C8AEA.3963@kabelfoon.nl>
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?
From: Kent M Pitman
Subject: Re: A multiple valued position?
Date: 
Message-ID: <sfwafer2yh2.fsf@world.std.com>
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.