Reputation: 2282
How do you bind multiple values returned from a function, inside a do loop? The following is obviously very wrong, but is something like this possible?
(do (((x y z) (3-val-fn) (3-val-fn)))
((equal y 'some-val) y)
(values x y z))
Or maybe there is a way to do this using multiple-value-bind?
Upvotes: 8
Views: 2514
Reputation: 1064
How about?:
(loop for (x y z) = (multiple-value-list (3-val-fn))
...etc)
I'd offer more but cannot understand the do-loop.
Upvotes: 8
Reputation: 139261
Multiple values in the standard iteration constructs is not really supported.
With LOOP your snippet might look like this:
(loop with x and y and z
do (setf (values x y z) (3-val-fn))
while (equal y 'some-val)
finally (return y)
do ...)
If I would need something like that often, I might define a do-mv
macro which would expand into above code. Code then would look like:
(do-mv ((x y z) (3-val-fn))
((equal y 'some-val) y)
...)
The advantage to use above is that it does not create lists from multiple values during each iteration. Creating lists out of multiple values kind of defeats the purpose of multiple values, which are there to return more than one values and allowing it to be implemented in an efficient way.
Upvotes: 10
Reputation: 21268
It's (sort-of) doable with do*
:
(defun foo (n)
(do* ((n n (1- n))
(values (multiple-value-list (truncate 17 n))
(multiple-value-list (truncate 17 n)))
(result (first values) (first values))
(remainder (second values) (second values)))
((< n 3) nil)
(format t "Result: ~d, remainder: ~d, n: ~d~%" result remainder n)))
Here we first convert the multi-valued function result into a list, bind that to a variable and then manually destructure it. But it is hard to read and should probably be avoided, unless the do
family of iteration constructs really happens to be a lot better choice than using loop
.
Upvotes: 1