RacketまたはSchemeのとまたはvalues
のlist
違いは何ですか? cons
どちらか一方を使用する方が良いのはいつですか?たとえば、 ?ではなくquotient/remainder
returnの場合の欠点は何でしょうか?(cons _ _)
(values _ _)
4 に答える
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
これらは、Scheme と Racket で意味的に同じです。どちらの場合でも、リターンを使用するには、リターンがどのように見えるかを知る必要があります。
values
に接続されcall-with-values
、特殊な形式のようなものlet-values
は、このプロシージャ コールのシンタックス シュガーにすぎません。ユーザーは、結果を利用するために使用する結果の形式を知る必要がありますcall-with-values
。多くの場合、リターンはスタック上で行われ、呼び出しもスタック上にあります。スキームを優先する唯一の理由values
は、プロデューサーのリターンとコンシューマーの呼び出しの間にオーバーヘッドがないことです。
cons
(または) を使用するとlist
、ユーザーは戻り値のデータ構造がどのように見えるかを知る必要があります。同様に、同じことをする代わりにvalues
使用できます。(およびその他)の代替として、マクロを作成するのは簡単です。apply
call-with-values
let-values
destructuring-bind
Common Lisp では、まったく異なります。提供する情報がさらにある場合はいつでも値を使用でき、ユーザーが最初の値のみを使用したい場合は、通常の手順として使用できます。quotient
したがって、CL の場合、同様に機能するため、バリアントとして提供する必要はありませんquotient/remainder
。複数の値を取る特殊なフォームまたはプロシージャを使用する場合にのみ、プロシージャがより多くの値を返すという事実は、Scheme と同じように機能します。これはvalues
、Scheme よりも CL の方が適しています。これは、複数のプロシージャーを作成する代わりに 1 つのプロシージャーを作成するだけで済むためです。
CL では、次のようにハッシュにアクセスできます。
(gethash 'key *hash* 't)
; ==> T; NIL
返された 2 番目の値を使用しないと、T がデフォルト値なのか実際に見つかった値なのかわかりません。ここでは、ハッシュでキーが見つからなかったことを示す 2 番目の値が表示されます。多くの場合、数値しかないことがわかっている場合は、デフォルト値がすでにキーが見つからなかったことを示しているため、その値を使用しません。ラケットで:
(hash-ref hash 'key #t)
; ==> #t
ラケットfailure-result
ではサンクになる可能性があるので大丈夫ですが、値がCLのように機能した場合は、代わりに複数の値が返されるに違いありません。CLバージョンとSchemeにはより多くのハウスキーピングがあると思います.Schemeは最小限の言語であるため、おそらく実装者に余分な作業を与えたくありませんでした.
編集:これを投稿する前に、同じトピックに関するAlexisのコメントを見逃しました
リストよりも複数の戻り値を使用することの見過ごされがちな実用的な利点の 1 つは、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
返された 2 つの値hello-goodbye
を 2 つの引数としてに渡しますstring-append
。多くのコンポジションを持つ関数型スタイルでコードを書いている場合、これは非常に便利で、などで値を明示的に渡すよりもはるかに自然ですcall-with-values
。