It seems like in order to use multiple return values in Racket, I have to either use define-values
or collect them into a list with (call-with-values (thunk (values-expr)) list)
. In the latter case, why would someone to choose to return multiple values instead of a list, if just have to collect them into a list anyway? Additionally, both of these are very wordy and awkward to work into most code. I feel like I must be misunderstanding something very basic about multiple-return-values. For that matter, how do I write a procedure accepting multiple return values?

- 1,661
- 19
- 32
-
http://docs.racket-lang.org/reference/values.html ...? – Will Ness Dec 13 '13 at 00:09
-
4Yeah, I mentioned those forms in the body, but my question is are those really the best we've got? If so, why do we even *have* multiple return values when a plain old list can do the same things better and easier? And I still don't know how to define a procedure *accepting* the result of something returning multiple values. – Matt G Dec 13 '13 at 00:20
-
you define this procedure as simple lambda with several arguments, and call it through call-with-values: `(call-with-values (lambda() (values 1 2)) (lambda(a b) ....))`. – Will Ness Dec 13 '13 at 00:37
-
Wow...this is like....exactly what I was googling. Good job! Also, neat, I didn't know about the `thunk` function. I had been making my own lambdas – George Mauer Dec 07 '19 at 22:02
4 Answers
Although I may be missing some of the Scheme history and other nuances, I'll give you my practical answer.
First, one rule of thumb is if you need to return more than 2 or 3 values, don't use multiple values and don't use a list. Use a struct
. That will usually be easier to read and maintain.
Racket's match
forms make it much easier to destructure a list return value -- as easy as define-values
:
(define (f)
(list 1 2))
(match-define (list a b) (f))
(do-something-with a b)
;; or
(match (f)
[(list a b) (do-something-with a b)])
If you have some other function, g
, that takes a (list/c a b)
, and you want to compose it with f
, it's simpler if f
returns a list. It's also simpler if both use a two-element struct
. Whereas call-with-values
is kind of an awkward hot mess, I think.
Allowing multiple return value is an elegant idea, because it makes return values symmetric with arguments. Using multiple values is also faster than lists or structs (in the current implementation of Racket, although it could work otherwise).
However when readability is a higher priority than performance, then in modern Racket it can be more practical to use a list
or a struct
, IMHO. Having said that I do use multiple values for one-off private helper functions.
Finally, there's a long, interesting discussion on the Racket mailing list.

- 16,100
- 6
- 36
- 53
Racket doc gives us the quintessential example why, in disguise:
> (let-values ([(q r) (quotient/remainder 10 3)])
(if (zero? r)
q
"3 does *not* divide 10 evenly"))
"3 does *not* divide 10 evenly"
We get two values directly, and use them separately in a computation that follows.
update: In Common Lisp, with its decidedly practical, down-to-the-metal, non-functional approach (where they concern themselves with each extra cons cell allocation), it makes much more sense, especially as it allows one to call such procedures in a "normal" way as well, automatically ignoring the "extra" results, kind of like
(let ([q (quotient/remainder 10 3)])
(list q))
But in Racket this is invalid code. So yeah, it looks like an extraneous feature, better to be avoided altogether.

- 70,110
- 9
- 98
- 181
-
-
2My question then is, what advantage do multiple return values have over a list? It seems a list could do the same thing, except in a way more consistent with the language, and easier to use. For example, (edit: had an implementation here, could not get it to format... whoops! Also, this comment was in front of Will's, but due to technical difficulties, I had to delete it and re-post it) – Matt G Dec 13 '13 at 00:33
-
`quotient/remainder` does not return a list. it returns two integers. Try `(list (quotient/reminder 10 3))` and `(call-with-values (lambda () (quotient/reminder 10 3)) list)`. – Will Ness Dec 13 '13 at 00:36
-
1Yes, that implementation is operating in the hypothetical world where we don't have multiple return values, and we just use a list. I don't mean to belabor this point, but if the advantage of multiple return values not being a list is that... they're not a list, then, well, that seems pretty dumb. – Matt G Dec 13 '13 at 00:38
-
if you don't want to create superfluous cons cells just to pass several values, then this is the mechanism for it. – Will Ness Dec 13 '13 at 00:42
-
2Bemoaning a handful too many cons cells in lisp is, in my opinion, kind of like complaining about a desert having a bucket too much sand. In the extremely abstractiony world of racket, where primitives are boxed, unboxed, resized, wrapped, and generally in all other ways "it-just-works"ified, it seems odd that this, what is essentially an implementation detail, is not only fully visible, but an important concept used often enough by the standard library that you have to use it too. But, I'm soapboxing now. Thanks for the information. – Matt G Dec 13 '13 at 00:50
-
one handful, and another, and one more, makes for too many handfuls... :) I understand where you're coming from; sometime in near enough future we'll all (but very few) will program in English. For sure. :) Maybe this current proliferation of programming languages is a world-wide conspiracy to provide employment for millions of programmers worldwide. :) Robots are coming to replace humans in production; we can't all be hairstylists for one another. Or can we? – Will Ness Dec 13 '13 at 00:55
-
3Your's is the only answer that is direct and to the point. How do you unpack multiple values from a function? This is how. Thanks! – Kaushik Ghose Sep 10 '15 at 00:06
Using list
as the consumer defeats the purpose of multiple values so in that case you could just have used lists to begin with. Multiple values is actually a way of optimization.
Semanticly returning a list and several values are similar, but where you return many values in a list effort goes into creation of cons cells to make the list and destructuring accessors to get the values at the other end. In many cases however, you wouldn't notice the difference in performance.
With multiple values the values are on the stack and (call-with-values (lambda () ... (values x y z)) (lambda (x y z) ...)
only checks the number to see if it's correct.. If it's ok you just apply the next procedure since the stack has it's arguments all set from the previous call.
You can make syntactic sugar around this and some popular ones are let-values
and SRFI-8 receive is a slightly simpler one. Both uses call-with-values
as primitive.

- 47,942
- 4
- 47
- 79
-
+1 for mentioning `receive`. That's the most concise way to deal with this non-sense. Who would have thought a Lisp would be afraid of lists? But here we are. `(require srfi/8)` then `(receive (q r) (quotient/remainder 10 3) r)`. – remcycles Dec 11 '22 at 07:10
values
is handy because it
- checks that the number of elements returned is correct
- destructures
For example, using
(define (out a b) (printf "a=~a b=~a\n" a b))
then
(let ((lst (list 1 2 3)))
(let ((a (first lst)) (b (second lst))) ; destructure
(out a b)))
will work even though lst
has 3 elements, but
(let-values (((a b) (values 1 2 3)))
(out a b))
will not.
If you want the same control and destructuring with a list, you can however use match
:
(let ((lst (list 1 2)))
(match lst ((list a b) (out a b))))
Note that he creation of the structure, e.g. (list 1 2)
vs (values 1 2)
is equivalent.

- 18,732
- 2
- 34
- 52
-
is `values` guaranteed to create structure, like `list`, or can it be implemented via stack mechanism as detailed in Sylwester's answer? – Will Ness Dec 13 '13 at 14:36
-
@WillNess That is an implementation detail. Semantically it's a structure because it's kept intact all the time. – uselpa Dec 13 '13 at 16:56
-
"semantically together" does not a structure make. :) "Structure" has a very specific meaning - a cons cell allocation. Semantics are orthogonal. Of course the two values are connected semantically, saying they cause the creation of a structure is something completely different. :) – Will Ness Dec 13 '13 at 17:06
-
@WillNess A structure is a representation of data. It is not limited to cons cells; a structure can be represented on a stack as well. See http://en.wikipedia.org/wiki/Data_structure. – uselpa Dec 13 '13 at 17:22
-
I'm talking Lisp parlance. :) And we *were* comparing `values` and `list`... :) Of course if an implementation performs a use analysis and allocates ephemeral conses on stack, it's a very good one indeed. – Will Ness Dec 13 '13 at 17:26