Mutiple value bind in do loop in Common Lisp
Asked Answered
C

3

8

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?

Condolent answered 13/1, 2017 at 6:10 Comment(3)
Something tells me this might reflect a deeper problem, viz,, using multiple-values inappropriately. Care to share the semantics?Safe
@Safe It wasn't in actual code. I was just experimenting with multiple values and trying to learn about them.Condolent
I think the problem is that CL has a million ways to do things so questions in the vacuum of any real-world context are essentially unanswerable. As in, maybe this is why LOOP does not offer syntactic sugar for destructuring multiple values: it never comes up given the appropriate use of multiple values. But you cast your curiosity in the form of how to do the same in a DO-LOOP, again not actually needing same. Again, CL is a vast language, I recommend the constraint of either a direct syntax question or actial requirement. Often the latter will be best answered with, "Oh, we use XXX for that"Safe
S
8

How about?:

(loop for (x y z) = (multiple-value-list (3-val-fn))
 ...etc)

I'd offer more but cannot understand the do-loop.

Safe answered 15/1, 2017 at 21:0 Comment(2)
That seems to be the easiest way to get there!Condolent
Best answer — I'd count on the good sense of the loop implementers to optimize away the spurious list creation but regardless, ephemeral conses are no big deal.Lilianaliliane
C
10

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.

Clere answered 13/1, 2017 at 9:1 Comment(0)
S
8

How about?:

(loop for (x y z) = (multiple-value-list (3-val-fn))
 ...etc)

I'd offer more but cannot understand the do-loop.

Safe answered 15/1, 2017 at 21:0 Comment(2)
That seems to be the easiest way to get there!Condolent
Best answer — I'd count on the good sense of the loop implementers to optimize away the spurious list creation but regardless, ephemeral conses are no big deal.Lilianaliliane
K
1

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.

Kirbee answered 16/1, 2017 at 10:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.