看来为了在Racket中使用多个返回值,我必须要么使用 define-values
或者将它们收集到列表中 (call-with-values (thunk (values-expr)) list)
。在后一种情况下,为什么有人会选择返回多个值而不是列表,如果只是必须将它们收集到列表中呢?此外,这些都非常冗长和笨拙,无法在大多数代码中使用。我觉得我必须误解一些关于多重返回值的基本信息。就此而言,我该如何编写程序 验收 多个返回值?
看来为了在Racket中使用多个返回值,我必须要么使用 define-values
或者将它们收集到列表中 (call-with-values (thunk (values-expr)) list)
。在后一种情况下,为什么有人会选择返回多个值而不是列表,如果只是必须将它们收集到列表中呢?此外,这些都非常冗长和笨拙,无法在大多数代码中使用。我觉得我必须误解一些关于多重返回值的基本信息。就此而言,我该如何编写程序 验收 多个返回值?
虽然我可能会遗漏一些计划历史和其他细微差别,但我会给你实际答案。
首先,一条经验法则是,如果您需要返回超过2或3个值,请不要使用多个值,也不要使用列表。用一个 struct
。这通常更容易阅读和维护。
球拍的 match
表单可以更容易地构造列表返回值 - 就像这样简单 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)])
如果你有其他功能, g
,这需要一个 (list/c a b)
,你想要用它来组成 f
,如果更简单 f
返回一个列表。如果两者都使用双元素也更简单 struct
。而 call-with-values
我认为,这是一种尴尬的热点。
允许多个返回值是一个优雅的想法,因为它使返回值与参数对称。使用多个值也比列表或结构更快(尽管如此,在当前的Racket实现中) 它可能会起作用)。
然而,当可读性比性能更高时,那么在现代Racket中使用a更为实用 list
或者a struct
, 恕我直言。话虽如此,我确实为一次性私人助手功能使用了多个值。
最后,还有一个 长而有趣的讨论 在Racket邮件列表上。
运用 list
因为消费者违背了多个价值观的目的,所以在这种情况下你可以使用列表开始。多个值实际上是一种优化方式。
语义上返回一个列表和几个值是相似的,但是在列表工作中返回许多值的地方就是创建cons单元以使列表和解构访问器在另一端获取值。但是,在许多情况下,您不会注意到性能上的差异。
使用多个值时,值位于堆栈上 (call-with-values (lambda () ... (values x y z)) (lambda (x y z) ...)
只检查数字是否正确..如果没关系,你只需应用下一个程序,因为堆栈的所有参数都是从前一次调用中设置的。
你可以围绕这个制作语法糖,一些流行的是 let-values
和 SRFI-8收到 是一个稍微简单的一个。两种用途 call-with-values
原始的。
values
很方便,因为它
例如,使用
(define (out a b) (printf "a=~a b=~a\n" a b))
然后
(let ((lst (list 1 2 3)))
(let ((a (first lst)) (b (second lst))) ; destructure
(out a b)))
即便如此 lst
有3个元素,但是
(let-values (((a b) (values 1 2 3)))
(out a b))
将不会。
如果您希望使用列表进行相同的控制和解构,则可以使用 match
:
(let ((lst (list 1 2)))
(match lst ((list a b) (out a b))))
注意,他创建了结构,例如, (list 1 2)
VS (values 1 2)
是等价的。
球拍文件 给我们一个典型的例子,为什么,伪装:
> (let-values ([(q r) (quotient/remainder 10 3)])
(if (zero? r)
q
"3 does *not* divide 10 evenly"))
"3 does *not* divide 10 evenly"
我们直接得到两个值,并在随后的计算中单独使用它们。
更新: 在Common Lisp中,凭借其明确实用的,实用的,非金属的,非功能性的方法(它们关注每个额外的缺陷单元分配),它更有意义,特别是因为它允许一个人调用这样的程序一种“正常”的方式,自动忽略“额外”的结果,有点像
(let ([q (quotient/remainder 10 3)])
(list q))
但在Racket中这是无效的代码。所以是的,它看起来像一个无关紧要的功能,最好完全避免。