手短に言えば、右結合性は、プログラマーが入力する内容とプログラムが実際に実行する内容とを一致させることにより、可読性を向上させることができるというものです。
したがって、「1 :: 2 :: 3
」と入力すると、リストがまったく異なる順序で返されるのではなく、List(1, 2, 3) が返されます。
それは、「1 :: 2 :: 3 :: Nil
」が実際には
List[Int].3.prepend(2).prepend(1)
scala> 1 :: 2 :: 3:: Nil
res0: List[Int] = List(1, 2, 3)
これは両方です:
- より読みやすい
- より効率的 (O(1) に対して
prepend
、仮想append
メソッドの O(n))
(Reminder, 本からの抜粋Programming in Scala )
メソッドが のような演算子表記法で使用されている場合、メソッド名がコロンで終わらない限り、 —のようa * b
に、メソッドは左側のオペランドで呼び出されます。
メソッド名がコロンで終わる場合、メソッドは右側のオペランドで呼び出されます。
したがって、 では、 でメソッドが呼び出され、次のように 1 が渡されます。a.*(b)
1 :: twoThree
::
twoThree
twoThree.::(1)
List の場合、追加操作の役割を果たします (リストは '1' の後に追加されて ' ' を形成しているように見えます1 2 3
が、実際にはリストの前に追加されるのは 1 です)。
リストへの追加にかかる時間はリストのサイズに比例して増加するのに対し、 :: を前に追加するには一定の時間がかかるため、クラス List は真の追加操作を提供しません。
myList :: 1
myList のコンテンツ全体を '1' に追加しようとしますが、これは myList に 1 を追加するよりも長くなります (' 1 :: myList
' のように)
注: ただし、演算子の結合性に関係なく、そのオペランドは常に左から右に評価されます。
したがって、 b が不変値への単なる参照ではない式である場合、 a ::: b は次のブロックとしてより正確に扱われます。
{ val x = a; b.:::(x) }
このブロックでは、a が b の前に評価され、この評価の結果がオペランドとして b の ::: メソッドに渡されます。
なぜ左結合と右結合の方法を区別するのですか?
1 :: myList
これにより、実際には右側の式に操作を適用しながら、通常の左結合操作 (' ') の外観を維持できます。
- それはより効率的です。
- しかし、逆の結合順 ('
1 :: myList
' vs. ' myList.prepend(1)
')の方が読みやすいです。
あなたが言うように、私の知る限り、「シンタックスシュガー」。たとえば、 の場合、それらは少し行き過ぎている
可能性があること
に注意してください(' ' 右結合演算子と同等です)。foldLeft
/:
コメントの一部を含めるには、少し言い換えます。
「追加」関数を左結合と見なす場合は、「 」と記述しますoneTwo append 3 append 4 append 5
。
ただし、oneTwo に 3、4、および 5 を追加すると (これは書かれている方法で想定されます)、O(N) になります。
「追加」の場合は「::」と同じです。そうではありません。実際には「プリペンド」用です
つまり、' a :: b :: Nil
' は ' ' 用List[].b.prepend(a)
です
'::' を先頭に追加しても左結合のままである場合、結果のリストは間違った順序になります。
List(1, 2, 3, 4, 5) を返すことを期待しますが、最終的には List(5, 4, 3, 1, 2) を返すことになります。これは、プログラマにとって予期しないことかもしれません。
それは、あなたがしたことは、左結合の順序であったからです:
(1,2).prepend(3).prepend(4).prepend(5) : (5,4,3,1,2)
したがって、右結合により、コードは戻り値の実際の順序と一致します。