マイナス記号「-」が一般にプラス記号と同じように過負荷にならないのはなぜですか?


64

プラス記号+は、加算と文字列の連結に使用されますが、そのコンパニオンであるマイナス記号、は-、通常、文字列のトリミングや減算以外の場合には表示されません。その理由や制限は何でしょうか?

JavaScriptの次の例を検討してください。

var a = "abcdefg";
var b = "efg";

a-b == NaN
// but
a+b == "abcdefgefg"

35
どの「yy」を削除する必要がありますか?
ガシャッハ

12
「+」記号の動作を使用する場合、最も適切なのは理にかなっています。
ディグビジェイヤダフ

46
二項+演算子が「数値の加算」と「文字列の連結」というまったく関係のない2つの意味でオーバーロードされるのは十分に悪いことです。ありがたいことに、いくつかの言語のような別個の連結演算子を提供する.(Perl5の、PHP)、~(Perl6の)、&(VB)、++...(ハスケル)、
アモン

6
@MasonWheelerを使用します->(仮想メソッド呼び出しには必ずポインターのような間接参照が含まれるため、Cでのメンバーアクセスの逆参照を検討してください)。.ますます一般的な慣習ですが、演算子を使用するためにメソッド呼び出し/メンバーアクセスを必要とする言語設計の法則はありません。Smalltalkにはメソッド呼び出し演算子がないことをご存知ですか?単純な並置object methodで十分です。
アモン

20
Python セットの減算のためにマイナスをオーバーロードします(ユーザー定義型でもオーバーロードできます)。Pythonセットは、交差/結合などのビット演算子のほとんどをオーバーロードします。
ケビン

回答:


116

要するに、人々がアルゴリズムを書きたいと思った文字列に対して、特に有用な減算のような操作はありません。

+オペレータは、一般に、添加剤の操作示しモノイドをつまり、同一要素と連想動作です。

  • A +(B + C)=(A + B)+ C
  • A + 0 = 0 + A = A

これらはすべて同じ代数構造を持っているため、整数の加算、文字列の連結、集合のユニオンなどにこの演算子を使用するのは理にかなっています。

1 + (2 + 3) == (1 + 2) + 3
1 + 0 == 0 + 1 == 1

"a" + ("b" + "c") == ("a" + "b") + "c"
"a" + "" == "" + "a" == "a"

そして、これを使用してconcat、「連結可能」なもののシーケンスで機能する関数のような便利なアルゴリズムを作成できます。

def concat(sequence):
    return sequence.reduce(+, 0)

減算はときに-巻き込ま、あなたは、通常の構造について話すグループ追加し、:ように、すべての要素Aのために-Aを

  • A + −A = −A + A = 0

そして、これは整数や浮動小数点の減算、またはセットの差のようなものには意味がありますが、文字列やリストにはあまり意味がありません。の逆は"foo"何ですか?

cancellative monoidと呼ばれる構造があり、これには逆関数はありませんが、キャンセルプロパティがあります。

  • A − A = 0
  • A − 0 = A
  • (A + B)− B = A

これはあなたが説明する構造で、ここで"ab" - "b" == "a""ab" - "c"定義されていません。この構造を使用する便利なアルゴリズムがあまりないというだけです。連結をシリアル化と考えると、何らかの解析に減算を使用できると思います。


2
セット(およびマルチセット)の減算は理にかなっています。シーケンスとは異なり、要素の順序は重要ではないためです。
CodesInChaos

@CodesInChaos:それらの言及を追加しましたが、グループの例としてセットを置くのは本当に快適ではありませんでした。通常、セットの逆を構築できないので、セットを形成するとは思いません。
ジョンパーディ

12
実際には、この+演算は数値に対して可換でもあります。つまりA+B == B+A、文字列の連結の悪い候補になります。これに加えて、混乱を招く演算子の優先順位により+、文字列の連結に歴史的な間違いが生じます。しかし、それは使用していることは事実だ-どんな文字列操作のためには...物事が非常に悪化し
ホルガー

2
@ダークホッグ:そうだね!PHP .はPerlから借用しています。それ~はおそらくPerl6にあります。
ジョンパーディ

1
@MartinBeckettしかし、あなたは行動がと混乱するかもしれないことがわかります.text.gz.text...
スパイダーボリス

38

2つの有効な文字列の連結は常に有効な操作ですが、その逆は当てはまりません。

var a = "Hello";
var b = "World";

a - bここに何がありますか?質問自体は有効ではないため、その質問に答える良い方法はありません。


31
@ DigvijayYadav、5個のリンゴから5個のマンゴーを削除する場合、-5個のマンゴーのカウンターが必要ですか?何もしませんか?広く受け入れられ、すべてのコンパイラーおよび言語のインタープリターにこの形式でこの演算子を使用できるように、これを十分に定義できますか?それがここでの大きな挑戦です。
JBキング

28
@DigvijayYadav:これを実装する2つの可能な方法を説明したばかりで、それぞれを有効と見なすには良い議論があります。:P
メイソンウィーラー

13
@smci 数値はブール値ではなく、ブール値は数値ではないため、5 + False明らかにエラーと思われます。
メイソンウィーラー

6
@JanDvorak:それについて特に「Haskelly」はありません。それが基本的な強い型付けです。
メイソンウィーラー

5
@DigvijayYadavだから(a+b)-b = a(願わくば!)(a-b)+bですがa、時には、が部分文字列であるかa+bどうかによって異なりますか?これはどんな狂気ですか?ba

28

-文字列操作の演算子には十分な「セマンティック結合」がないためです。演算子は、オペランドでオーバーロードが何をするかが完全に明確で、文字列の減算がそのバーを満たさない場合にのみオーバーロードする必要があります。

したがって、メソッド呼び出しが推奨されます。

public string Remove(string source, string toRemove)
public string Replace(string source, string oldValue, string newValue)

C#言語では+、フォームが

var result = string1 + string2 + string3;

の代わりに

var result = string.Concat(string1, string2, string3);

セマンティックの観点からは、関数呼び出しの方がおそらく「正しい」場合でも、便利で間違いなく読みやすいです。

+オペレータは、実際には、この文脈で一つのことを意味することができます。これはのための真ではありません-差し引いた文字列の概念は(関数呼び出し曖昧であるため、Replace(source, oldValue, newValue)との""ようnewValueパラメータは、すべての疑いを削除し、関数がサブストリングを変更するために使用することができ、ちょうどそれらを削除しません)。

もちろん、問題は、演算子のオーバーロードが演算子に渡される型に依存していることであり、数値があったはずの場所に文字列を渡すと、予期しない結果が得られる可能性があります。さらに、多くの連結(ループ内)では、StringBuilderオブジェクトを使用する+ことをお勧めします。使用するたびに新しい文字列が作成され、パフォーマンスが低下する可能性があるためです。そのため、+演算子はすべてのコンテキストで適切ではありません。

+文字列の連結に対して演算子が行うよりもセマンティックな凝集性が優れている演算子のオーバーロードがあります。以下に2つの複素数を追加するものを示します。

public static Complex operator +(Complex c1, Complex c2) 
{
    return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}

8
+1 2つの文字列AとBを考えると、ABを「Aの末尾から末尾のBを削除する」、「AのどこかからBのインスタンスを削除する」、「AのどこかからBのすべてのインスタンスを削除する」 、または「Bで見つかったすべての文字をAから削除します。」
コートアンモン

8

Groovyの言語は認めていません-

println('ABC'-'B')

返却値:

AC

そして:

println( 'Hello' - 'World' )

返却値:

Hello

そして:

println('ABABABABAB' - 'B')

返却値:

AABABABAB

11
興味深い-だから、最初の出現を削除することを選択しますか?完全に直感に反する動作の良い例です。
ハルク

9
したがって、('ABABABABA' + 'B') - 'B'開始値とほとんど同じではありません'ABABABABA'
CVn

3
@MichaelKjörlingOTOH、(A + B) - A == BAとBごとに。左減算と呼ぶことができますか?
ジョンドヴォルザーク

2
Haskellに++は連結があります。任意のリストで機能し、文字列は単なる文字のリストです。また\\、を持ちます。これは、右引数内のすべての要素の最初の出現を左引数から削除します。
ジョンドボラック

3
これらの例が、文字列にマイナス演算子を使用するべきではない理由です。一貫性がなく、直感的な動作ではありません。「-」について考えるとき、「一致する文字列の最初のインスタンスが発生した場合はそれを削除し、そうでなければ何もしない」とは思わないでしょう。
エンダーランド

6

多くの場合、プラス記号はおそらく文脈上意味がありますが、Pythonの反例(おそらくルールを証明する例外)はsetオブジェクトであり、これは以下を提供しますが、提供し-ません+

>>> set('abc') - set('bcd')
set(['a'])
>>> set('abc') + set('bcd')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'set' and 'set'

+意図があいまいになる可能性があるため、記号を使用することは意味がありません-交差点または結合を設定することを意味しますか?代わりに、|結合および&交差に使用します。

>>> set('abc') | set('bcd')
set(['a', 'c', 'b', 'd'])
>>> set('abc') & set('bcd')
set(['c', 'b'])

2
これは、数学では集合の減算が定義されているが、集合の加算は定義されていないためです。
Mehrdad

「-」の使用は危険なようです。本当に必要なのは、整数でビットごとの算術演算を実行するときにも役立つ「ではない」演算子です。30の〜&7が24の場合、〜&をセットで使用すると&および|にうまく適合します。セットには〜演算子はありませんが。
-supercat

1
set('abc') ^ set('bcd')set(['a', 'd'])対称差について尋ねている場合、を返します。
アーロンホール

3

-」は、さまざまな部分を同じ単語に結合するために、いくつかの複合語(「オンサイト」など)で使用されます。-プログラミング言語で異なる文字列を結合するために「」を使用しないのはなぜですか?それは完全に理にかなっていると思います!この+ナンセンスで地獄に!

ただし、これをもう少し抽象的な角度から見てみましょう。

文字列代数をどのように定義しますか?あなたはどのような事業を展開し、どのような法律が彼らに適用されますか?彼らの関係はどうでしょうか?

曖昧さがまったくないかもしれないことを覚えておいてください!これは不可能だと言っていても、考えられるすべてのケースを明確に定義する必要があります。代数が小さければ小さいほど、これは簡単です。

たとえば、2つの文字列を実際に加算または減算するとはどういう意味ですか?

2つの文字列(たとえば、let a = "aa"b = "bb")を追加するaabbと、結果はa + b

いかがb + a?それでしょうbbaaか?どうしてaabb?加算aaの結果から減算するとどうなりますか?あなたのストリングには、マイナスの量の概念がありaaますか?

次に、この回答の先頭に戻りspaceshuttle、文字列の代わりに置き換えます。一般化するために、どのタイプの操作も定義されているのか、定義されていないのですか?

私が作ろうとしているのは、何かのために代数を作成することを妨げるものは何もないということです。意味のある操作を見つけるのは難しいかもしれませんし、それに役立つ操作さえ見つけるのは難しいかもしれません。

文字列の場合、連結は、これまでに出会った唯一の賢明な方法です。操作を表すためにどのシンボルが使用されるかは関係ありません。


1
「文字列の場合、連結は、私がこれまでに遭遇した唯一の賢明な方法です。それでは、Pythonに反対'xy' * 3 == 'xyxyxy'ですか?
smci

3
@smciそれは単なる繰り返しとしての加算である、確かに?
jonrsharpe

スペースシャトルを連結する適切な演算子は何ですか?
-Mr.Mindor

4
@ Mr.Mindor backspace ...スペースシャトル間のスペースを削除します。
YoungJohn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.