有没有办法从 Racket 中返回 `(values 1 2 3)` 的函数访问第 n 个返回值?

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

给出这样的函数

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

我能否以某种方式调用 (foo) 并仅获取其中一个值,例如 (first (foo))?我想为此定义一个辅助函数,但它必须与被调用函数的元数相匹配,这感觉不对。

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

嗯,简单的方法就是使用 define-values 绑定所有三个值,然后忽略后两个。不过,这有点不令人满意。更好的解决方案可能是使用 match-define-values,这将允许您明确忽略其他两个。

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

不过,这并不能真正让您将 return 多个值的函数包装在另一个函数中以获得第一个值。

Racket 并没有真正提供很多用于操作多个值的内置工具,这实际上是设计使然。其他包可能包含您想要的功能——例如,sugar 包提供 values->list.

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

这不在核心库中是有原因的:它是一种反模式。从一个函数返回多个值是你应该谨慎做的事情。 Racket return 多值中的函数并不多,因为它们使程序更难推理。它们组合得不好,而且它们很少是解决问题的最佳方法。

在某些情况下,多个 return 值 有用的,通常是出于性能原因编写同时执行两件事的函数时。例如,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 与同时调用 takedrop 相同,但效率更高。