Reputation: 1576
I've been thinking about the following problem. Suppose I'm dealing with a function returning multiple values, such as truncate
. Is there a clever way to reverse the order of values that get returned? I'm talking about something more clever than e.g.
(multiple-value-bind (div rem) (truncate x y)
(values rem div))
Upvotes: 1
Views: 132
Reputation: 486
To have it as clean/consistent as multiple-value-bind, you could define a macro such as this:
(defmacro reverse-multiple-value-bind (args f &rest body)
`(multiple-value-bind ,(reverse args)
,f
,@body))
Then you have
>> (multiple-value-bind (x y) (floor 3.7) (print x) (print y))
3
0.70000005
and
> (reverse-multiple-value-bind (x y) (floor 3.7) (print x) (print y))
0.70000005
3
Upvotes: 0
Reputation: 58588
This problem can be solved more cleverly by writing a higher order function whose input is a function that returns some (values a b)
, and which returns a function which calls that function, but returns (values b a)
. In other words a value reversing combinator:
(defun val-rev (function)
(lambda (&rest args)
(multiple-value-bind (a b) (apply function args)
(values b a))))
Though inside the definition of this function we are doing the cumbersome thing you don't want (capturing the values with m-v-bind
and reversing with values
) this is encapsulated in the combinator and just an implementation detail. It's probably more efficient than consing up a value list and reversing it. Also, it specifically targets the first two values. If a function returns four values, A B C D
, then reversing the multiple-value-list
means that the first two return values will be C D
. However, if we just bind the first two and reverse them, then we bet B A
. Reversing the first two (or only two) values is clearly not the same as reversing all values.
Demo:
[1]> (truncate 17 3)
5 ;
2
[2]> (funcall (val-rev #'truncate) 17 3)
2 ;
5
Note that in a Lisp-1 dialect, the invocation loses the added noise of #'
and funcall
, reducing simply to: ((val-rev truncate) 17 3)
.
val-rev
is kind of a dual of the flip
higher order function which you see in some functional languages, which takes a binary function and returns a binary function which is that function, but with the arguments reversed.
Upvotes: 1
Reputation: 1542
I don't know how clever this is, but here's what you want:
(reverse (multiple-value-list (the-function-that-returns-multiple-values)))
multiple-value-list being the key, here.
To return these again as separate values, use values-list:
(values-list (reverse (multiple-value-list (the-function-that-returns-multiple-values))))
This whole page may be enlightening.
Upvotes: 5