Mengapa tanda minus, '-', umumnya tidak kelebihan muatan dengan cara yang sama dengan tanda plus?

64

Tanda plus +digunakan untuk penambahan dan untuk penggabungan string, tetapi pasangannya: tanda minus -, umumnya tidak terlihat untuk memotong string atau kasus lain selain pengurangan. Apa yang bisa menjadi alasan atau batasan untuk itu?

Pertimbangkan contoh berikut dalam JavaScript:

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

a-b == NaN
// but
a+b == "abcdefgefg"
Digvijay Yadav
sumber
35
"yy" mana yang harus dihapus?
Gashach
12
Jika saya mengikuti perilaku tanda '+', maka yang paling masuk akal adalah.
Digvijay Yadav
46
Sudah cukup buruk bahwa +operator biner kelebihan beban dengan dua arti yang sama sekali tidak terkait "penambahan numerik" dan "penggabungan string". Untungnya, beberapa bahasa menyediakan operator gabungan yang terpisah seperti .(Perl5, PHP), ~(Perl6), &(VB), ++(Haskell), ...
amon
6
@MasonWheeler Mereka menggunakan ->(pikirkan akses anggota dereferencing dalam C, karena panggilan metode virtual harus melibatkan tipuan seperti pointer). Tidak ada hukum desain bahasa yang mengharuskan pemanggilan metode / akses anggota untuk menggunakan .operator, meskipun itu adalah konvensi yang semakin umum. Tahukah Anda bahwa Smalltalk tidak memiliki operator panggilan metode? Penjajaran sederhana object methodsudah cukup.
amon
20
Python melakukan overload minus, untuk mengatur pengurangan (dan itu bisa kelebihan beban di tipe yang ditentukan pengguna juga). Kumpulan Python juga membebani sebagian besar operator bitwise untuk persimpangan / gabungan / dll.
Kevin

Jawaban:

116

Singkatnya, tidak ada operasi pengurangan yang sangat berguna pada string yang orang ingin tuliskan algoritmanya.

The +Operator umumnya menunjukkan operasi aditif monoid , yaitu, operasi asosiatif dengan elemen identitas:

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

Masuk akal untuk menggunakan operator ini untuk hal-hal seperti penambahan integer, penggabungan string, dan penyatuan gabungan karena mereka semua memiliki struktur aljabar yang sama:

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

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

Dan kita dapat menggunakannya untuk menulis algoritme praktis seperti concatfungsi yang bekerja pada urutan hal-hal yang “dapat digabungkan”, misalnya:

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

Ketika pengurangan -terlibat, Anda biasanya berbicara tentang struktur grup , yang menambahkan −A terbalik untuk setiap elemen A, sehingga:

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

Dan sementara ini masuk akal untuk hal-hal seperti integer dan pengurangan floating-point, atau bahkan perbedaan, itu tidak masuk akal untuk string dan daftar. Apa kebalikannya "foo"?

Ada struktur yang disebut monoid pembatalan , yang tidak memiliki invers, tetapi memiliki properti pembatalan , sehingga:

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

Ini adalah struktur yang Anda gambarkan, di mana "ab" - "b" == "a", tetapi "ab" - "c"tidak didefinisikan. Hanya saja kami tidak memiliki banyak algoritma yang bermanfaat yang menggunakan struktur ini. Saya kira jika Anda menganggap Rangkaian sebagai serialisasi, maka pengurangan dapat digunakan untuk beberapa jenis parsing.

Jon Purdy
sumber
2
Untuk set (dan multi-set) pengurangan masuk akal, karena tidak seperti urutan, urutan elemen tidak masalah.
CodesInChaos
@CodesInChaos: Saya menambahkan sebutan untuk mereka, tetapi saya tidak begitu nyaman menempatkan set sebagai contoh grup — saya tidak percaya mereka membentuk satu, karena Anda biasanya tidak bisa membuat kebalikan dari set.
Jon Purdy
12
Sebenarnya, +operasi juga komutatif untuk angka, yaitu A+B == B+A, yang membuatnya menjadi kandidat yang buruk untuk penggabungan string. Ini, ditambah operator yang didahulukan dari operator yang membingungkan menjadikan +penggabungan string sebagai kesalahan historis. Namun, memang benar bahwa menggunakan -operasi string apa pun membuat segalanya lebih buruk ...
Holger
2
@ Arkhogg: Benar! PHP meminjam .dari Perl; ada ~di Perl6, mungkin yang lain.
Jon Purdy
1
@ MartinBeckett tetapi Anda dapat melihat bahwa perilakunya mungkin membingungkan dengan .text.gz.text...
Boris the Spider
38

Karena rangkaian dari dua string yang valid selalu merupakan operasi yang valid, tetapi yang sebaliknya tidak benar.

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

Apa yang seharusnya a - bada di sini? Benar-benar tidak ada cara yang baik untuk menjawab pertanyaan itu, karena pertanyaan itu sendiri tidak valid.

Mason Wheeler
sumber
31
@DigvijayYadav, jika Anda menghapus 5 mangga dari 5 apel apakah harus ada penghitung -5 mangga? Apakah itu tidak melakukan apa-apa? Bisakah Anda mendefinisikan ini dengan cukup baik sehingga dapat diterima secara luas dan dimasukkan ke semua kompiler dan juru bahasa untuk menggunakan operator ini dalam formulir ini? Itulah tantangan besar di sini.
JB King
28
@DigvijayYadav: Jadi, Anda baru saja menggambarkan dua cara yang mungkin untuk mengimplementasikan ini, dan ada argumen yang bagus untuk menganggap masing-masing sebagai valid, jadi kami sudah membuat kekacauan gagasan menentukan operasi ini. : P
Mason Wheeler
13
@smci Sepertinya bagi saya 5 + Falseseharusnya kesalahan , karena angka bukan boolean dan boolean bukan angka.
Mason Wheeler
6
@ JanDvorak: Tidak ada yang khusus "Haskelly" tentang itu; itu pengetikan dasar yang kuat.
Mason Wheeler
5
@DigvijayYadav Jadi (a+b)-b = a(mudah-mudahan!), Tetapi (a-b)+bkadang-kadang a, kadang a+b- kadang tergantung pada apakah bsubstring aatau tidak? Kegilaan apa ini?
28

Karena -operator untuk manipulasi string tidak memiliki cukup "kohesi semantik." Operator hanya boleh kelebihan beban ketika benar-benar jelas apa kelebihan beban dengan operannya, dan pengurangan string tidak memenuhi bilah itu.

Akibatnya, panggilan metode lebih disukai:

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

Dalam bahasa C #, kami menggunakan +untuk rangkaian string karena bentuk

var result = string1 + string2 + string3;

dari pada

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

nyaman dan bisa dibilang lebih mudah dibaca, meskipun pemanggilan fungsi mungkin lebih "benar," dari sudut pandang semantik.

The +operator dapat benar-benar hanya berarti satu hal dalam konteks ini. Hal ini tidak berlaku untuk -, karena gagasan mengurangkan string adalah ambigu (fungsi panggilan Replace(source, oldValue, newValue)dengan ""sebagai newValueparameter menghapus semua keraguan, dan fungsi tersebut dapat digunakan untuk mengubah substring, bukan hanya menghapusnya).

Masalahnya, tentu saja, adalah bahwa operator kelebihan beban tergantung pada jenis yang diteruskan ke operator, dan jika Anda melewati string di mana nomor seharusnya, Anda mungkin mendapatkan hasil yang tidak Anda harapkan. Selain itu, untuk banyak rangkaian (yaitu dalam satu lingkaran), suatu StringBuilderobjek lebih disukai, karena setiap penggunaan +menciptakan string baru, dan kinerja dapat menderita. Jadi +operator bahkan tidak sesuai dalam semua konteks.

Ada kelebihan operator yang memiliki keterpaduan semantik yang lebih baik daripada yang dilakukan +operator untuk penggabungan string. Inilah satu yang menambahkan dua bilangan kompleks:

public static Complex operator +(Complex c1, Complex c2) 
{
    return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}
Robert Harvey
sumber
8
+1 Dengan dua string, A dan B, saya dapat menganggap AB sebagai "menghapus trailing B dari akhir A," "menghapus instance B dari suatu tempat di A," "menghapus semua instance B dari suatu tempat di A , "atau bahkan" hapus semua karakter yang ditemukan dalam B dari A. "
Cort Ammon
8

Bahasa Groovy memungkinkan -:

println('ABC'-'B')

pengembalian:

AC

Dan:

println( 'Hello' - 'World' )

pengembalian:

Hello

Dan:

println('ABABABABAB' - 'B')

pengembalian:

AABABABAB
Wim Deblauwe
sumber
11
Menarik - jadi ia memilih untuk menghapus kejadian pertama? Contoh yang baik untuk perilaku yang sepenuhnya kontra-intuitif.
Hulk
9
Oleh karena itu, kami memiliki nilai yang ('ABABABABA' + 'B') - 'B'mendekati nilai awal 'ABABABABA'.
CVn
3
@ MichaelKjörling OTOH, (A + B) - A == Buntuk setiap A dan B. Dapatkah saya menyebutnya pengurangan kiri?
John Dvorak
2
Haskell memiliki ++untuk penggabungan. Ini berfungsi pada daftar apa pun dan string hanyalah daftar karakter. Itu juga memiliki \\, yang menghilangkan kejadian pertama dari setiap elemen dalam argumen kanan dari argumen kiri.
John Dvorak
3
Saya merasa seperti contoh-contoh ini persis mengapa tidak boleh ada operator minus untuk string. Itu perilaku yang tidak konsisten dan tidak intuitif. Ketika saya memikirkan "-" Saya yakin tidak berpikir, "hapus instance pertama dari string yang cocok, jika itu terjadi, jika tidak lakukan apa-apa."
enderland
6

Tanda plus mungkin secara kontekstual masuk akal dalam banyak kasus, tetapi contoh tandingan (mungkin pengecualian yang membuktikan aturan) dalam Python adalah objek yang ditetapkan, yang menyediakan -tetapi tidak +:

>>> 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'

Tidak masuk akal untuk menggunakan +tanda itu karena niatnya bisa ambigu - apakah itu berarti mengatur persimpangan atau persatuan? Alih-alih, ini digunakan |untuk gabungan dan &untuk persimpangan:

>>> set('abc') | set('bcd')
set(['a', 'c', 'b', 'd'])
>>> set('abc') & set('bcd')
set(['c', 'b'])
Aaron Hall
sumber
2
Ini lebih mungkin karena pengurangan set didefinisikan dalam matematika, tetapi penambahan set tidak.
Mehrdad
Penggunaan "-" tampaknya cerdik; yang benar-benar dibutuhkan adalah operator "tetapi tidak" yang juga berguna ketika melakukan aritmatika bitwise dengan bilangan bulat. Jika 30 ~ & 7 adalah 24, maka menggunakan ~ & dengan set akan cocok dengan & & | meskipun set tidak memiliki ~ operator.
supercat
1
set('abc') ^ set('bcd')kembali set(['a', 'd']), jika Anda bertanya tentang perbedaan simetris.
Aaron Hall
3

" -" digunakan dalam beberapa kata majemuk (misalnya, "di tempat") untuk menggabungkan bagian-bagian yang berbeda ke dalam kata yang sama. Mengapa kita tidak menggunakan " -" untuk menggabungkan berbagai string dalam bahasa pemrograman? Saya pikir itu akan masuk akal! Persetan dengan +omong kosong ini !

Namun, mari kita coba melihat ini dari sudut yang lebih abstrak.

Bagaimana Anda mendefinisikan aljabar string? Operasi apa yang akan Anda miliki, dan hukum apa yang berlaku bagi mereka? Akan seperti apa hubungan mereka?

Ingat, mungkin sama sekali tidak ada ambiguitas! Setiap kasus yang mungkin harus didefinisikan dengan baik, bahkan jika itu berarti mengatakan tidak mungkin untuk melakukan ini! Semakin kecil aljabar Anda, semakin mudah hal ini dilakukan.

Misalnya, apa sebenarnya arti menambahkan atau mengurangi dua string?

Jika Anda menambahkan dua string (misalnya, biarkan a = "aa"dan b = "bb"), apakah Anda akan mendapatkan aabbhasil a + b?

Bagaimana dengan b + a? Apakah itu akan terjadi bbaa? Mengapa tidak aabb? Apa yang terjadi jika Anda mengurangi aahasil penambahan Anda? Apakah string Anda memiliki konsep jumlah negatif aadi dalamnya?

Sekarang kembali ke awal jawaban ini dan gantikan spaceshuttlestring. Untuk menggeneralisasi, mengapa operasi apa pun didefinisikan atau tidak didefinisikan untuk jenis apa pun?

Maksud saya adalah, bahwa tidak ada yang menghentikan Anda dari membuat aljabar untuk apa pun. Mungkin sulit untuk menemukan operasi yang berarti, atau bahkan operasi yang bermanfaat untuknya.

Sebagai gantinya, penggabungan adalah satu-satunya yang masuk akal yang pernah saya temui. Tidak masalah simbol apa yang digunakan untuk mewakili operasi.

Zavior
sumber
1
"Untuk string, penggabungan adalah satu-satunya yang masuk akal yang pernah saya temui" . Lalu apakah Anda tidak setuju dengan Python 'xy' * 3 == 'xyxyxy'?
smci
3
@smci itu hanya perkalian-sebagai-pengulangan-tambahan , tentunya?
jonrsharpe
apa operator yang tepat untuk menggabungkan spaceshuttles?
Mr.Mindor
4
@ Mr.Mindor backspace ... untuk menghapus ruang di antara spaceshuttles.
YoungJohn