Search code examples
schemelispracketmultiple-return-values

Is there a way to access n-th returned value from a function returning `(values 1 2 3)` in Racket?


Given a function like this

(define (foo) (values 1 2 3))

can I somehow call (foo) and only get one of the values, such as (first (foo))? I thought about defining a helper function for this, but it has to match the arity of the called function, which doesn't feel right.

(define (first x y z) x)
(first (foo))

Solution

  • Well, the easy way is just to use define-values to bind all three values, then ignore the second two. This is a little unsatisfying, though. A nicer solution might be to use match-define-values, which will allow you to explicitly ignore the other two.

    (match-define-values (a _ _) (values 1 2 3))
    

    Still, this doesn't really just let you wrap a function that returns multiple values in another function just to get the first value.

    Racket doesn't really provide very many built-in facilities for manipulating multiple values, and this is actually by design. Other packages may contain functionality you'd like—for example, the sugar package provides values->list.

    (first (values->list (values 1 2 3)))
    

    This isn't in the core libraries for a reason: it's an antipattern. Returning multiple values from a function is something that you should probably do sparingly. Not many functions in Racket return multiple values because they make programs harder to reason about. They don't compose well, and they're rarely the best solution to a problem.

    There is a situation in which multiple return values are useful, and that's usually when writing functions that do two things at once for performance reasons. For example, quotient/remainder just returns the values of quotient and remainder, but since it's done in a single function, it can be more efficiently implemented. Similarly, split-at is the same as calling both take and drop, but it's also more efficient.