5

Racket 或 Scheme 中的valuesand listor有什么区别?cons什么时候使用一个比另一个更好?例如,如果quotient/remainderreturn(cons _ _)而不是会有什么缺点(values _ _)

4

4 回答 4

7

早在 2002 年,George Caswell 在 comp.lang.scheme 中提出了这个问题。随后的线程很长,但有很多见解。讨论表明意见分歧。

https://groups.google.com/d/msg/comp.lang.scheme/ruhDvI9utVc/786ztruIUNYJ

我当时的回答:

>    What are the motivations behind Scheme's multiple return values feature?
> Is it meant to reflect the difference in intent, or is there a
> runtime-practical reason?

I imagine the reason being this.

Let's say that need f is called by g. g needs several values from f.
Without multiple value return, f packs the values in a list (or vector),
which is passed to g. g then immediately unpacks the list.

With multple values, the values are just pushed on the stack. Thus no
packing and unpacking is done.

Whether this should be called an optimization hack or not, is up to you.

--
Jens Axel Søgaard

We don't need no side-effecting         We don't need no allocation
We don't need no flow control           We don't need no special-nodes
No global variables for execution       No dark bit-flipping for debugging
Hey! did you leave the args alone?      Hey! did you leave those bits alone?
(Chorus)                  -- "Another Glitch in the Call", a la Pink Floyd
于 2015-04-09T16:50:55.767 回答
4

它们在 Scheme 和 Racket 中的语义相同。在这两种情况下,您都需要知道使用它时返回的样子。

values被连接到call-with-values并且特殊的形式就像let-values是这个过程调用的语法糖。用户需要知道结果的形式以使用call-with-values结果。返回通常在堆栈上完成,调用也在堆栈上。支持 Scheme 的唯一原因values是生产者返回和消费者调用之间没有开销。

使用cons(或list),用户需要知道返回的数据结构是什么样的。正如values你可以使用apply而不是call-with-values做同样的事情。作为(以及更多)的替代品,制作宏let-values很容易。destructuring-bind

在 Common Lisp 中,情况完全不同。如果您要提供更多信息,则始终可以使用值,并且如果用户只想使用第一个值,她仍然可以将其用作正常过程。因此,对于 CL,您不需要提供quotient变体,因为quotient/remainder它也可以正常工作。只有当您使用特殊形式或采用多个值的过程时,该过程确实返回更多值的事实才能与使用 Scheme 的方式相同。这values在 CL 中是比 Scheme 更好的选择,因为您只需编写一个而不是更多的过程即可。

在 CL 中,您可以像这样访问哈希:

(gethash 'key *hash* 't)
; ==> T; NIL

如果不使用返回的第二个值,则不知道 T 是默认值还是找到的实际值。在这里,您会看到第二个值,表明在散列中找不到密钥。如果您知道只有数字,通常您不会使用该值,默认值已经表明未找到密钥。在球拍中:

(hash-ref hash 'key #t)
; ==> #t

在球拍failure-result中可以是一个重击,所以你可以通过,但我敢打赌,如果值确实像 CL 中那样工作,它会返回多个值。我认为 CL 版本和 Scheme 有更多的内务管理,作为一种简约的语言,也许不想给实现者额外的工作。

于 2015-04-09T14:07:36.393 回答
4

编辑:在发布之前错过了亚历克西斯对同一主题的评论

使用多个返回值而不是列表的一个经常被忽视的实际优势是 Racket 的compose“只适用于”返回多个值的函数:

(define (hello-goodbye name)
  (values (format "Hello ~a! " name)
          (format "Goodbye ~a." name)))

(define short-conversation (compose string-append hello-goodbye))

> (short-conversation "John")
"Hello John! Goodbye John."

产生的函数compose将把返回的两个值hello-goodbye作为两个参数传递给string-append. 如果您正在编写具有大量组合的函数式代码,这将非常方便,并且比在您自己周围显式传递值更自然call-with-values

于 2015-04-10T03:28:40.310 回答
3

这也与您的编程风格有关。如果你使用values,那么它通常意味着你想显式地返回n 个值。使用cons, listorvector通常意味着您想要返回一个包含某些内容的值。

总是有优点/缺点。For values:它可能会在某些实现上使用更少的内存。调用者需要使用let-values或其他多个值特定的语法。(我希望我可以let像 CL 一样使用。)

For consor other types:可以使用letorlambda来接收返回值。您需要显式解构它以获得您想要使用的值car或其他过程。

使用哪个以及何时使用?再次取决于您的编程风格和具体情况,但如果返回值不能在一个对象中表示(例如商和余数),那么最好使用values使过程的含义更清晰。如果返回值是一个对象(例如一个人的姓名和年龄),那么使用cons其他构造函数(例如记录)可能会更好。

于 2015-04-09T07:00:47.303 回答