One of the interesting features of Lisp is its support for returning multiple values from a function, without bundling the values in a special container. Languages such as Python and Ruby support multi-value return (although there are subtle differences from Lisp). In C++11, we can use std::make_tuple() and std::tie().
To take an example, in Lisp, the built-in function floor returns both the quotient and reminder. However, the caller may use only the first value (quotient) and ignore the second value:
(setf quotient (floor 7 3))
Here the call to floor looks exactly like a call to a regular function that returns a single value, and as expected, the variable quotient gets the value 2 (the reminder is discarded).
Let us first see how a function can return multiple values. The following function computes both the sum and difference of two numbers passed as arguments:
(defun sum-diff (num1 num2)
(values (+ num1 num2) (- num1 num2)))
The values function bundles all its arguments (which are evaluated) into a value list to be used by the caller. It is important to keep in mind that returning multiple values is not the same as returning a list of many values. The former is more efficient and flexible.
OK. How do we consume multiple values from a function? We use the multiple-value-bind construct.
(multiple-value-bind (s d) (sum-diff)
(format t “Sum = ~D, Difference = ~D~%” s d))
multiple-value-bind is a macro, whose first argument is a list of variables, the second argument is a multi-valued expression, and the rest are forms that are evaluated in the context of the variable bindings.
Going back to the floor example, we can use it thus:
(multiple-value-bind (quot rem) (floor 7 3)
(format t “Quotient = ~D, Reminder = ~D~%” quot rem))
if there are more variables than values returned by the multi-valued function, the extra variables get nil. If there are fewer variables than returned values, then only the corresponding values are bound.
When do we write such multi-valued functions? There are two scenarios:
* The values computed are logically related. In the case of floor, the quotient and reminder are logically related
* It is more efficient to compute the values together because most of the steps are common
(Please note that the sum-diff function falls into neither of the two scenarios, and hence is not a good example of a multi-valued function.)
As an interesting use of the values function, the following swaps the state of the two variables a and b:
(setf (values a b) (values b a))
Recent Comments