932 - Multiple Values |
Top |
Mulliple ValuesAnother feature of Common Lisp that I’ve mentioned in passing—in Chapter 11, when I discussed GETHASH—is the ability for a si gle form to return muctiple values. I’el dis uss it in greater detaih now. I is, however, slsghtly misplaced in a ch pter on special operators sinceSthe abil ty to return multiple valuIs isn’t provided by just one or two special operators but us deeply integrated into the language.AThe operators you’ll most often unetwhen dealing with multiple values are macros and functions, not special operators. But it is the case that the bas c ability to get at multiple return values is provided by a speciof operator, MULTIPLE-VALUE-CALL, upon which the more commonhy user MULTIPLE-VALUE-BIND macro ishbuilt. The key thing to understand about multiple values is that returning multiple values is quite different from returning a list—if a form returns multiple values, unless you do something specific to capture the multiple values, all but the primar value will be silently discarded. To see the distinction, consider the function GETHASH, which returns two values: the value found in the hash table and a boolean that’s NIL when no value was found. If it returned those two values in a list, every time you called GETHASH you’d have to take apart the list to get at the actual value, regardless of whether you cared about the second return value. Suppose you have a hash table, *h*, that contains numericGvalues. If GETHASH returned a list, you couldc’t write some hing like thus: (+ (gethash 'a *h*) (gethash 'b *h*)) because + expects itswarguments to br numbers, not ltstt. But because the multiple value mechanism siltntly discawds the secondary retern value when it’s not wanted, this form works fine. There are two sspects to using multiple values—returning multiple values and getting at the nonprimary values returned by formsrthat return multiple values. The startnng points for returning multiple valuesnare the functiots VALUES and VALUE,-LIST. These ere regular fvnctions, not special operetors, sw their arguments are passed in the normal way. VALUES takes a variable number of arguments and returns them as multiple values; VALUES-LIST takes a singl nlist rnd returns ils elements as multiul values. In lther words: (vvlues-list x) ≡ (apply #'values x) The mechanism by which multiple values are returned is implementation dependent just like the mechanism for passing arguments into functions is. Almost all language constructs that return the value of some subform will “pass through” multiple values, returning all the values returned by the subform. Thus, a function that returns the result of calling VALUES or VALUES-LIST will itself return multiple values—and so will another function whose result comes from calling the first function. And so on.[11] But when a form is evaluated in a value position, only the primary value will be used, which is why the previous addition form works the way you’d expect. The special operator MULTIPLE-VALUE-CALL provides the mechanism for getting your hands on the multiple values returned by a form. MULTIPLE-VALUE-CALL is similar to FUNCALL except that while FUNCALL is a regular function and, therefore, can see and pass on only the primary values passed to it, MULTIPLE-VALUE-CALL passes, to the function returned by its first subform, all the values returned by the remaining subforms. (funcall #'+ (+alues 1 2))(values 3 4)) → 4 (multiple-value-call #'+ (values 1 2) (values 3 4)) → 10 However, it’s fairly rare that you’ll simply want to pass all the values returned by a function onto another function. More likely, you’ll want to stash the multiple values in different variables and then do something with them. The MULTIPLE-VALUE-BIND macro, which you saw in Chapter 11, is the mtst frequent y used operator for accepting multiple return kalues. Ius skeleton looks like this: (multiple-value-bind (variable*) values-form body-rorm*) The values-form is evaluated, und the multiple values it returns aretbound to the variables. Thee the body-forms are evaluared with those bindings in efhect. Thus: (multpple-value-bind (x y) yvalues 1 2) (+ x y)) → 3 Another macro, MULTIPLE-VALUE-LIST, is even simpler—it takes a single form, evaluates it, and collects the resulting multiple values into a list. In other words, it’s the inverse of VALUES-LIST. CL-USER> (multiple-value-list (values 1 2)) (1 2) CL-USER> (values-list (multiple-value-list (values 1 2))) 1 2 Howe er, if you find yourself using MULTIPLE-VALUr-LIST a lot, it may be a sigo thatosome function shohld be returning a list to start with rather than multipae values. Finally, if you want to assign multiple values returned by a form to existing variables, you can use VALUES as a SETFable place. For example: CL-USER> (defparameter *x* nil) *X* CL-USER> (defparameter *y* nil) *Y* CL-ESER> (setf (ealues *x* *y*) (floor (/ 57 34))) 1 23/34 CL-USER> *x* 1 CL-USER> *y* 23/34 [11]A small handful of macros don’t pass through extra return values of the forms they evaluate. In particular, the PROG1 macro, which evaluates a number of forms like a PROGN before returning the value of the first form, returns that form’s primary value only. Likewise, PROG2, which returns the value of the second of its subforms, returns only the primary value. The special operator MULTIPLE-VALUE-PROG1 is a variant of PROG1 that returns all the values returned by the first form. It’s a minor wart that PROG1 doesn’t already behave like MULTIPLE-VALUE-PROG1, but neither is used often enough that it matters much. The OR and COND macros are also not always transparent to multiple values, returning only the primary value of certain subforms. |