빼기 부호 '-'가 일반적으로 더하기 부호와 같은 방식으로 오버로드되지 않는 이유는 무엇입니까?


64

더하기 부호 +는 더하기 및 문자열 연결에 사용되지만 그 동반자 인 빼기 부호 -는 일반적으로 문자열을 자르거나 빼기 이외의 다른 경우에는 표시되지 않습니다. 그 이유나 한계는 무엇입니까?

JavaScript에서 다음 예제를 고려하십시오.

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

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

35
어떤 "yy"를 제거해야합니까?
gashach

12
'+'부호의 동작으로 가면 가장 옳은 것이 좋습니다.
Digvijay Yadav

46
이진 +연산자에 완전히 관련이없는 두 가지 의미 "숫자 추가"및 "문자열 연결"이 오버로드되는 것은 충분하지 않습니다 . 고맙게도 일부 언어는 .(Perl5, PHP), ~(Perl6), &(VB), ++(Haskell) 등과 같은 별도의 연결 연산자를 제공합니다 .
amon

6
@MasonWheeler 사용합니다 ->(가상 메서드 호출에는 반드시 포인터와 같은 간접 참조가 포함되므로 C에서 역 참조 멤버 액세스를 생각하십시오). .연산자 를 사용하기 위해 메소드 호출 / 멤버 액세스를 요구하는 언어 설계법은 없지만 점점 더 일반적인 규칙입니다. 스몰 토크에 메소드 호출 연산자가 없다는 것을 알고 있습니까? 간단한 병치 object method만으로 충분합니다.
amon

20
파이썬 빼기를 설정 하기 위해 빼기 과부하를 수행 합니다 (그리고 사용자 정의 유형에도 과부하가 걸릴 수 있습니다). 파이썬 세트는 또한 교차 / 연합 등의 비트 연산자 대부분을 오버로드합니다.
Kevin

답변:


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 모노 이드 역원이없는,하지만 가지고 취소 할 수 있도록, 속성을 :

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

이것은 당신이 설명하는 구조 "ab" - "b" == "a"이지만, "ab" - "c"정의되지 않았습니다. 이 구조를 사용하는 유용한 알고리즘이 많지 않다는 것입니다. 연결을 직렬화로 생각하면 일종의 구문 분석에 뺄셈을 사용할 수 있습니다.


2
집합 (및 다중 집합)의 경우 빼기는 의미가 있습니다. 시퀀스와 달리 요소의 순서는 중요하지 않기 때문입니다.
코드 InChaos

@CodesInChaos : 나는 이것에 대한 언급을 추가했지만 그룹의 예로 세트를 놓는 것은 실제로 편안하지 않았습니다. 일반적으로 세트의 역을 구성 할 수 없기 때문에 세트를 형성한다고 생각하지 않습니다.
Jon Purdy

12
실제로, +연산은 숫자에 대해서도 정류 적입니다. 즉 A+B == B+A, 문자열 연결 의 나쁜 후보가됩니다. 이것은 혼란스러운 연산자 우선 순위와 함께 +문자열 연결에 역사적 실수를 사용하여 렌더링합니다 . 그러나 -문자열 작업 을 위해 사용 하면 상황이 훨씬 악화 된다는 것이 사실입니다 …
Holger

2
@ Darkhogg : 맞아! .Perl에서 빌린 PHP ; 그건 ~, Perl6에 아마도 다른 사람.
Jon Purdy

1
@MartinBeckett하지만 동작이 혼동 될 수 있음을 알 수 있습니다 .text.gz.text.
Boris the Spider

38

두 개의 유효한 문자열을 연결하는 것은 항상 유효한 작업이지만 그 반대가 아닙니다.

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

a - b여기에 무엇이 있어야 합니까? 질문 자체가 유효하지 않기 때문에 그 질문에 대답하는 좋은 방법은 없습니다.


31
@DigvijayYadav, 5 개의 사과에서 5 개의 망고를 제거하면 -5 망고의 카운터가 있어야합니까? 아무것도하지 않습니까? 이 연산자를이 형식으로 사용하기 위해 광범위하게 받아 들여지고 언어의 모든 컴파일러와 인터프리터에 넣을 수있을 정도로 충분히 정의 할 수 있습니까? 이것이 큰 도전입니다.
JB King

28
@DigvijayYadav : 방금 이것을 구현하는 두 가지 가능한 방법을 설명했고, 각각을 유효한 것으로 간주하는 좋은 주장이 있으므로, 우리는 이미이 작업을 지정한다는 아이디어를 혼란스럽게 만들고 있습니다. : P
Mason Wheeler

13
@smci 숫자가 부울이 아니고 부울이 숫자가 아니기 때문에 5 + False분명히 오류 일 것 같습니다 .
메이슨 휠러

6
@ JanDvorak : 그것에 대해 특별히 "Haskelly"는 없습니다. 그것은 기본적인 강력한 타이핑입니다.
메이슨 휠러

5
@DigvijayYadav 그래서 (a+b)-b = a(잘하면!)하지만, (a-b)+b때때로 a, 때로는 a+b경우에 따라 b의 문자열입니다 a여부? 이게 무슨 광기 야?

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)""는 AS newValue매개 변수는 모든 의심을 제거하고 기능이 아니라 그들을 제거 문자열을 변경하는 데 사용할 수있는이).

물론 문제는 연산자 오버로드가 연산자에 전달되는 유형에 따라 달라지며 숫자가 있어야 할 문자열을 전달하면 예상치 못한 결과를 얻을 수 있다는 것입니다. 또한 많은 연결 (예 : 루프)의 경우, StringBuilder매번 사용할 때마다 +새로운 문자열 을 생성하고 성능이 저하 될 수 있으므로 객체가 바람직 합니다. 따라서 +연산자는 모든 상황에 적합하지 않습니다.

+문자열 연결에 대해 연산자 보다 의미 론적 응집력이 우수한 연산자 과부하가 있습니다 . 다음은 두 개의 복소수를 추가하는 것입니다.

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

8
+1 두 개의 문자열 A와 B가 주어지면 AB를 "A의 끝에서 후행 B를 제거합니다", "A의 어딘가에서 B의 인스턴스를 제거합니다." "A의 어딘가에서 B의 모든 인스턴스를 제거합니다. , "또는"B에서 발견 된 모든 문자를 A에서 제거합니다. "
Cort Ammon

8

그루비 언어는 허용 않습니다 -:

println('ABC'-'B')

보고:

AC

과:

println( 'Hello' - 'World' )

보고:

Hello

과:

println('ABABABABAB' - 'B')

보고:

AABABABAB

11
흥미 롭기 때문에 첫 번째 항목을 제거하기로 선택 했습니까? 완전히 반 직관적 인 행동에 대한 좋은 예입니다.
Hulk

9
따라서 ('ABABABABA' + 'B') - 'B'시작 값과 거의 동일하지 않습니다 'ABABABABA'.
CVn

3
@ MichaelKjörling OTOH, (A + B) - A == B모든 A와 B에 대해 왼쪽 뺄셈이라고 부를 수 있습니까?
John Dvorak

2
하스켈은 ++연결해야합니다. 모든 목록에서 작동하며 문자열은 문자 목록입니다. 또한 \\왼쪽 인수에서 오른쪽 인수의 모든 요소가 처음으로 나타나는 것을 제거합니다.
John Dvorak

3
나는이 예제가 정확히 문자열에 대한 빼기 연산자가 없어야하는 이유라고 생각합니다. 일관성이없고 직관적 인 동작이 아닙니다. "-"를 생각할 때, "일치하는 문자열의 첫 번째 인스턴스를 제거하고, 그렇지 않으면 아무 것도하지 마십시오."
enderland

6

더하기 부호는 상황에 따라 문맥 상 의미가있을 수 있지만, 파이썬의 반례 (아마도 규칙을 증명하는 예외)는 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'])대칭 차이를 묻는 경우를 반환합니다 .
Aaron Hall

3

" -"는 다른 단어를 같은 단어로 결합하기 위해 일부 복합 단어 (예 : "현장")에 사용됩니다. -프로그래밍 언어에서 다른 문자열을 함께 결합하기 위해 " "를 사용하지 않는 이유는 무엇 입니까? 나는 그것이 의미가 있다고 생각합니다! 이 +말도 안돼!

그러나 이것을 좀 더 추상적 인 각도에서 보도록합시다.

문자열 대수를 어떻게 정의 하시겠습니까? 어떤 운영을하고 어떤 법률을 보유하고 있습니까? 그들의 관계는 무엇입니까?

모호성이 전혀 없다는 것을 기억하십시오! 이것이 불가능하다고 말하는 경우에도 가능한 모든 경우를 잘 정의해야합니다! 대수가 작을수록 더 쉽습니다.

예를 들어, 실제로 두 문자열을 더하거나 빼는 것은 무엇을 의미합니까?

(예를 들어 보자 두 개의 문자열을 추가하는 경우 a = "aa"b = "bb"), 당신은 얻을 것 aabb의 결과로 a + b?

어때요 b + a? 그럴까요 bbaa? 왜 안돼 aabb? aa추가 결과에서 빼면 어떻게됩니까 ? 문자열에 음수 개념이 aa있습니까?

이제이 답변의 시작 부분으로 돌아가 spaceshuttle문자열 대신 대체 하십시오. 일반화하기 위해 어떤 유형의 조작이 정의되거나 정의되지 않은 이유는 무엇입니까?

내가하려고하는 요점은 아무것도 대수를 만들지 못하게하는 것이 없다는 것입니다. 의미있는 작업을 찾기가 어렵거나 유용한 작업을 찾기가 어려울 수도 있습니다.

문자열의 경우 연결은 내가 본 적이있는 유일한 현명한 것입니다. 작업을 나타내는 데 사용되는 기호는 중요하지 않습니다.


1
"문자열의 경우, 연결은 내가 본 적이있는 유일한 현명한 것" 입니다. 그렇다면 파이썬에 동의하지 'xy' * 3 == 'xyxyxy'않습니까?
smci

3
@smci 반복되는 반복 곱셈 일까요?
jonrsharpe

우주 왕복선을 연결하는 적절한 연산자는 무엇입니까?
Mr.Mindor

4
@ Mr.Mindor 백 스페이스 ... spaceshuttles 사이의 공간을 제거합니다.
YoungJohn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.