Racket中多个值和普通元组之间的区别?

时间:2015-04-09 05:03:03

标签: scheme tuples racket cons multiple-value

在Racket或Scheme中,valueslistcons之间有什么区别?什么时候使用一个比另一个好?例如,如果quotient/remainder返回(cons _ _)而不是(values _ _),会有什么不利之处?

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:4)

它们在Scheme和Racket中在语义上是相同的。在这两者中,您需要知道返回的使用方式。

valuescall-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是默认值还是找到的实际值。在这里,您会看到第二个值,表示在散列中找不到密钥。如果您知道只有数字,那么您通常不会使用该值,默认值已经表明未找到密钥。在Racket中:

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

在球拍中failure-result可以是一个thunk,所以你得到了,但我敢打赌它将返回多个值,而不是如果值像CL一样工作。我假设CL版本和Scheme有更多内务管理,是一种简约语言,也许并不想给实现者额外的工作。

答案 2 :(得分:4)

编辑:在发布此

之前错过了Alexis对同一主题的评论

在列表上使用多个返回值的一个经常忽略的实际优点是,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之类的方法明确传递值更自然。

答案 3 :(得分:3)

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

总有利弊。对于values:它可能会在某些实现中使用更少的内存。调用者需要使用let-values或其他多个值特定语法。 (我希望我可以像CL一样使用let。)

对于cons或其他类型:您可以使用letlambda来接收返回值。您需要使用car或其他过程明确解构它以获得所需的值。

使用哪个以及何时使用?同样取决于您的编程风格和具体情况,但如果返回的值不能在一个对象中表示(例如商和余数),那么最好使用values来制作程序&#39 ; s意思更清楚。如果返回值是一个对象(例如一个人的姓名和年龄),那么使用cons或其他构造函数(例如记录)可能更好。