Is the values function in Common Lisp just syntactic sugar for packaging multiple values into a list that gets destructured by the caller?. I am asking because I thought Common Lisp supports "true" multiple value return rather than returning a tuple or a list as in other languages, such as python. Someone just told me that it's just syntactic sugar, so I would like someone to kindly explain it. To try to understand the type that is returned by the values function, I typed (type-of (values 1 2 3))
, and the output was BIT
. I searched in the Common Lisp reference for that and I couldn't find it mentioned in the datatypes section. Also, can anyone share some resources that suggest how the values function is implemented in Common Lisp?. Thank you.
Some built-in Common Lisp functions, such as floor, return multiple values; those that do are so documented. These specify a form to evaluate and an indication of where to put the values returned by that form. The expression (values) returns zero values.
Use defun to define your own functions in LISP. Defun requires you to provide three things. The first is the name of the function, the second is a list of parameters for the function, and the third is the body of the function -- i.e. LISP instructions that tell the interpreter what to do when the function is called.
Remember, Lisp returns the value of whatever expr was last executed in a function as its value. If n==0 , the above returns 0. If n > 0 , it returns the result of the + expr. If you need a multi-step test (for example to make sure you're not being passed a negative number), cond is the way (as mentioned earlier).
The primitive procedures for handling multiple values are values and call-with-values . values is used for returning multiple values from a procedure. This is done by placing a call to values with zero or more arguments in tail position in a procedure body.
The language Common lisp is described in the ANSI standard INCITS 226-1994 (R2004) and has many implementations. Each can implement multiple values as it sees fit, and they are allowed, of course, to cons up a list for them (in fact, the Emacs Lisp compatibility layer for CL does just that - but it is, emphatically and intentionally, not a Common Lisp implementation).
However, the intent of this facility is to enable passing (at least some) multiple values without consing (i.e., without allocating heap memory) and all CL implementations I know of do that. In this sense the multiple values facility is an optimization.
Of course, the implementation of this feature can be very different for different platforms and scenarios. E.g., the first few (say, 20 - required by the standard) are stored in a static of thread-local vector, the next several (1000?) are allocated on the stack, and the rest (if needed) are allocated on the heap as a vector or list.
E.g., the function floor
returns two values. If you write
(setq a (floor 10 3))
you capture only the first one and discard the second one, you need to write
(setf (values q r) (floor 10 3))
to capture both values. This is similar to what other languages might express as
q,r = floor(10,3)
using tuples, except that CL does not allocate memory to pass (just a few) multiple values, and the other languages often do.
IOW, one can think of multiple values as an ephemeral struct.
Note that CL can convert multiple values to lists:
(destructuring-bind (q r) (multiple-value-list (floor 10 3)) ; use q & r here ...)
instead of the more efficient and concise
(multiple-value-bind (q r) (floor 10 3) ; use q & r here ...)
CL does not have a special type for the "multiple value object" exactly because it does not allocate a separate object to pass around multiple values. In this sense one can, indeed, claim that values
is syntactic sugar.
However, in CL one can declare a function type returning multiple values:
(declaim (ftype (real &optional real) (values real real)) floor)
This means that floor
returns two values, both real
s (as opposed to returning a value of type (values real real)
), i.e., in this case one might claim abuse of notation.
In your specific case, type-of
is an ordinary function (i.e., not a macro or special operator). You pass it a single object, 1, because, unless you are using multiple-value-bind
and friends, only the first value is used, so
(type-of (values 1 2 3))
is identical to
(type-of 1)
and type of 1 is bit
.
One use of values
is to control the return values of a function. Normally a CL function's return values are those of the last form. Sometimes it is not desirable, e.g., the last form return multiple values and you want your function to return one value (or none, like void
in C
):
(defun 2values (x y) (floor y x)) (defun 1value (x y) (values (floor y x))) (defun no-values (x) (print x) (values))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With