似乎为了在Racket中使用多个返回值,我要么使用define-values,要么使用(call-with-values (thunk (values-expr)) list)将它们收集到一个列表中。在后一种情况下,如果只需要将多个值收集到列表中,为什么会有人选择返回多个值而不是一个列表呢?此外,这两种代码在大多数代码中的工作都非常冗长和笨拙。我觉得我一定是误解了关于多重回报价值观的一些非常基本的东西。因此,如何编写接受多个返回值的过程?
发布于 2013-12-13 15:04:14
虽然我可能遗漏了一些计划的历史和其他细微之处,但我会给你我的实际答案。
首先,一个经验法则是,如果需要返回2或3个以上的值,不要使用多个值,也不要使用列表。使用struct。这通常会更容易阅读和维护。
Racket的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中,尽管是否则就能工作了)。
然而,当可读性比性能更高时,在现代球拍中使用list或struct,IMHO可能更实用。话虽如此,我确实对一次性私人助手函数使用了多个值。
最后,在球拍邮件列表上有一个长时间有趣的讨论。
发布于 2013-12-13 00:22:05
球拍医生给了我们一个典型的例子,为什么伪装成这样:
> (let-values ([(q r) (quotient/remainder 10 3)])
(if (zero? r)
q
"3 does *not* divide 10 evenly"))
"3 does *not* divide 10 evenly"我们直接得到两个值,并在下面的计算中分别使用它们。
更新:在通用Lisp中,由于其明确的实用、低端、非功能的方法(他们关注每一个额外的单元分配),它更有意义,尤其是它允许人们以“正常”的方式调用这些过程,自动忽略“额外”结果,就像这样。
(let ([q (quotient/remainder 10 3)])
(list q))但在球拍中,这是无效的代码。所以是的,这看起来像是一个无关的特性,最好完全避免。
发布于 2013-12-13 13:28:49
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)是等价的。
https://stackoverflow.com/questions/20556746
复制相似问题