Mengapa lebih banyak bahasa tidak memiliki kemampuan untuk membandingkan suatu nilai dengan lebih dari satu nilai lainnya? [Tutup]

10

Pertimbangkan yang berikut ini:

if(a == b or c)

Dalam sebagian besar bahasa, ini perlu ditulis sebagai:

if(a == b or a == c)

yang sedikit rumit dan mengulang informasi.

Saya tahu sintaks sampel saya di atas agak kikuk, tetapi saya yakin ada cara yang lebih baik untuk menyampaikan gagasan itu.

Mengapa tidak banyak bahasa yang menawarkannya? Apakah ada masalah kinerja atau sintaksis?

Zeroth
sumber
6
SQL menawarkan bahwa: di mana A IN (B, C)
thursdaysgeek
4
Saya tidak meminta bahasa yang menawarkannya, atau bisa memilikinya, tetapi mengapa tidak banyak bahasa yang menawarkannya? Apakah ada masalah kinerja atau sintaksis?
Zeroth
8
untuk menggeneralisasi jawaban @ thursdaysgeek, dalam sebagian besar bahasa, biasanya Anda melakukannya dengan mengatur konten. (Atau daftar atau tuple jika itu lebih mudah.) Itu berfungsi sama dan menghindari beberapa masalah sintaksis yang berpotensi rumit. Dari contoh Anda, apakah "b atau c" berarti set "{b, c}" atau atau operator seperti || ? Dengan python "b atau c" berarti "nilai b jika benar, atau nilai c"
Rob
4
Pada dasarnya ini adalah masalah sintaksis. Masalah yang dihadapi adalah memiliki cara intuitif untuk menyatukan perbedaan antara "b atau c" dan "b atau dengan c".
YoungJohn
2
Ini cukup aneh untuk kasus khusus a == b or c, dan bahkan tidak IMHOsebelum IMHO.

Jawaban:

24

Masalah sintaks adalah - bahwa itu memerlukan sintaks.

Apa pun sintaksis bahasa Anda, orang yang menggunakan bahasa harus mempelajarinya. Kalau tidak, mereka berisiko melihat kode dan tidak tahu apa fungsinya. Jadi itu umumnya dianggap hal yang baik jika bahasa memiliki sintaksis sederhana yang menangani banyak kasus.

Dalam contoh spesifik Anda, Anda mencoba mengambil operator infiks (fungsi yang mengambil dua argumen tetapi ditulis Argument1 Operator Argument2) dan mencoba memperluasnya ke beberapa argumen. Itu tidak bekerja dengan sangat bersih karena seluruh titik operator infiks, sejauh ada satu, adalah untuk menempatkan operator tepat di antara 2 argumen. Memperluas ke (Argument1 Operator Argument2 MagicallyClearSymbol Argument3...)tampaknya tidak menambah banyak kejelasan Equals(Arg1,Arg2,...). Infix juga biasanya digunakan untuk meniru konvensi matematika yang sudah dikenal banyak orang, yang tidak akan berlaku untuk sintaks alternatif.

Tidak akan ada masalah kinerja tertentu yang terkait dengan ide Anda, selain itu parser harus berurusan dengan tata bahasa dengan satu atau dua aturan produksi, yang mungkin memiliki sedikit efek pada kecepatan parsing. Ini mungkin membuat beberapa perbedaan untuk bahasa yang dikompilasi ditafsirkan atau JIT, tetapi mungkin tidak perbedaan besar.

Masalah yang lebih besar dengan idenya adalah bahwa membuat banyak kasus khusus dalam suatu bahasa cenderung merupakan ide yang buruk .

psr
sumber
1
Selain itu: Scala memiliki operator infiks dengan sejumlah argumen yang arbitrer, karena operator infiks hanyalah pemanggilan metode tanpa a .. Jadi mereka ditulis sebagai arg1 op (arg2, arg3). Tidak persis cantik, tetapi dibutuhkan di beberapa tempat dalam konteks bahasa itu.
amon
bagaimana dengan if my_var in (a, b)itu? bukankah ini lebih merupakan pertanyaan menggunakan alat yang tepat untuk pekerjaan itu?
Poin bagus. Sintaks bahasa harus merupakan hal yang esensial dari bahasa tersebut, dan kemudian Anda membangun perpustakaan di atasnya. Jika bahasanya terlalu berantakan dengan gula sintaksis "membantu", itu akan menjadi lebih sulit untuk digunakan. Tidak semua orang membutuhkan, a == b or csementara yang lain inginkan a == b or c but not d. IMO di situlah fungsi utilitas / perpustakaan datang untuk menyelamatkan.
Allan
Mungkin yang dibutuhkan adalah sarana yang dengannya suatu metode dapat menentukan bahwa panggilan dengan jumlah argumen sewenang-wenang harus ditangani sebagai beberapa panggilan, dengan hasil yang digabungkan dalam beberapa cara. Jika f().Equals(a,b,c); dapat dievaluasi karena (var temp=f(); temp.Equals(a)||temp.Equals(b)||temp.Equals(c))sintaksinya akan sempurna, tetapi jika itu dievaluasi karena int[] arr = {a,b,c}; f().Equals(arr);itu tidak akan begitu baik, terutama jika array baru harus dibuat untuk setiap panggilan.
supercat
6

Karena ini bukan masalah, dan menyelesaikannya pada dasarnya memberikan manfaat nol, tetapi menerapkannya akan menghasilkan biaya yang tidak nol.

Fungsi berbasis rentang yang ada dan sedemikian rupa sehingga hampir setiap bahasa memang menawarkan dapat bekerja dengan baik dalam situasi ini jika skala ke ukuran di mana a == b || a == ctidak akan memotongnya.

DeadMG
sumber
2
+1, tetapi saya pikir jawabannya akan ditingkatkan dengan menunjukkan satu atau dua dari "fungsi berbasis rentang yang ada yang secara praktis setiap bahasa [penawaran]", supaya alternatif ini menjadi lebih jelas.
Avner Shahar-Kashtan
Bisakah Anda membuktikan bahwa itu "pada dasarnya memberikan manfaat nol, tetapi menerapkannya membawa biaya bukan nol"?
Darek Nędza
3
@ DarekNędza Babak kedua tidak boleh diperdebatkan: Setiap fitur harus dipikirkan, diimplementasikan, diuji, didokumentasikan, dan didukung. Tidak satu pun dari langkah-langkah itu gratis di bawah metrik yang masuk akal (waktu orang, biaya peluang, kompleksitas, biaya moneter jika ada yang dibayar untuk mengerjakannya, dan sebagainya).
@ AvnerShahar-Kashtan Setuju - bagi saya, tidak jelas bagaimana tampilannya, katakanlah, java, atau sh, atau zsh? Ok, dia mungkin telah menyiratkan bahasa 'modern'. Asyik?
Volker Siegel
Di PHP, akan terlihat seperti in_array($a, [$b, $c, $d, $e, $f]). : P
cHao
6

Beberapa bahasa memang memiliki fitur seperti itu. Misalnya dalam Perl6 kita bisa menggunakan persimpangan , yang merupakan "superposisi" dari dua nilai:

if $a == any($b, $c) {
    say "yes";
}

# syntactic sugar for the above
if $a == $b | $c {
    say "yes";
}

Persimpangan memungkinkan kami untuk mengekspresikan operasi pada set data yang cukup ringkas, mirip dengan cara operasi skalar mendistribusikan koleksi dalam beberapa bahasa. Misalnya menggunakan Python dengan numpy, perbandingan dapat didistribusikan ke semua nilai:

import numpy as np
2 == np.array([1, 2, 3])
#=> np.array([False, True, False], dtype=np.bool)
(2 == np.array([1, 2, 3])).any()
#=> True

Namun, ini hanya berfungsi untuk tipe primitif tertentu.

Mengapa persimpangan bermasalah? Karena operasi pada persimpangan mendistribusikan nilai-nilai yang terkandung, objek persimpangan itu sendiri berperilaku seperti proxy untuk pemanggilan metode - sesuatu yang bisa ditangani oleh beberapa jenis sistem selain dari pengetikan bebek.

Ketik masalah sistem dapat dihindari jika persimpangan seperti itu hanya diizinkan sebagai sintaks khusus di sekitar operator pembanding. Tetapi dalam kasus ini, mereka sangat terbatas sehingga mereka tidak menambah nilai yang cukup untuk ditambahkan ke bahasa yang waras. Perilaku yang sama dapat diekspresikan menggunakan operasi yang ditetapkan atau mengeja semua perbandingan secara manual, dan sebagian besar bahasa tidak percaya menambahkan sintaks yang berlebihan jika sudah ada solusi yang sangat bagus.

amon
sumber
Contoh numpy khusus itu dapat ditulis ulang lebih jelas sebagai 2 in [1, 2, 3]. Di sisi lain, jika numpy memiliki .all()atau sesuatu, python polos setara tidak hampir ringkas.
Izkata
@Izkata Saya secara khusus tidak menggunakan operasi yang ditetapkan. Sementara contoh saya memang menggunakan ==operator, kami juga bisa menggunakan <- di mana Anda insekarang? Persimpangan lebih umum daripada yang ditetapkan tes keanggotaan, karena operasi pada persimpangan mendistribusikan ke semua anggota - (x|y).fooadalah x.foo|y.foo, sampai persimpangan akhirnya runtuh ke nilai tunggal. Kode NumPy yang disediakan menunjukkan terjemahan Pers6 yang persis sama tetapi lebih bertele-tele, dengan asumsi tipe primitif.
amon
2

Dalam bahasa dengan makro, mudah untuk menambahkan sesuatu seperti itu jika belum ada di sana. Pertimbangkan Racket

(define-syntax-rule (equal-any? a b ...)
  (or (equal? a b) ...))
(equal-any? "a" "b" "a")
> #t

Dalam bahasa lain tanpa metaprogramming, mungkin Anda dapat memformulasikannya kembali sebagai set / daftar yang memeriksa keanggotaan:

if a ∈ {b, c}
Phil
sumber
2
Dua yang pertama memeriksa apakah semua argumen sama; OP ingin memeriksa apakah argumen pertama sama dengan yang berikut ini. Anehnya, cuplikan ketiga yang Anda perlihatkan menghargai itu.
@ Dave Maaf, saya salah paham. Saya sudah mengeditnya.
Phil
2

Dalam beberapa bahasa (populer) ==operator tidak transitif. Misalnya dalam JavaScript 0sama dengan keduanya ''dan '0', tetapi kemudian ''dan '0'tidak sama dengan satu sama lain. Lebih banyak kebiasaan semacam itu di PHP.

Ini berarti a == b == cakan menambah ambiguitas lain, karena dapat menghasilkan hasil yang berbeda tergantung pada apakah itu ditafsirkan sebagai (a == b) & (a == c)atau (a == b) & (a == c) & (b == c).

Konrad Morawski
sumber
2

Dalam sebagian besar bahasa, ini seharusnya dapat dicapai secara sepele dengan menulis suatu Infungsi, jadi mengapa menjadikannya bagian dari bahasa aktual?

Linq, misalnya, memiliki Contains().

Baiklah, untuk semua yang Anda ajak, inilah implementasi saya di C #:

public static bool In<T>(this T obj, params T[] values)
{
    for(int i=0; i < values.Length; i++)
    {
        if (object.Equals(obj, values[i]))
            return true;
    }
    return false;
}
Robert Harvey
sumber
Itu beroperasi pada rentang nilai run-time, bukan tuple karena kode OP dapat dinyatakan.
DeadMG
Sepertinya, hanya karena mudah, bukan berarti itu tidak boleh dilakukan. Ini ... pertimbangkan konstruksi. Mengapa kita selalu harus menulis semua bagian fungsionalitas dan algoritme ini secara manual, berulang kali dan lagi dan lagi?
Zeroth
5
@Eroth mungkin Anda menulis hal yang sama berulang kali, tetapi yang lain cenderung menggunakan mekanisme abstraksi yang ditawarkan oleh bahasa mereka. Jika Anda melihat diri Anda menulis a == b || a == cberulang kali, mungkin inilah saatnyaequals_any(a, {b, c})
amon
Implementasi "berisi" tidak mudah diperluas untuk mencakup hal-hal seperti if (a > (b or c))dan if (a mod (b or c) == 2).
tobyink
1
Apakah ada yang mengatakan pedants? :) Ini adalah loop foreach, jadi tidak ada ivariabel. Dan secara keseluruhan tampaknya ditulis setelah Anda memiliki hari yang panjang :) Karena meletakkan keduanya return truedan return falsedi dalam loop di sini berarti tidak ada cara itu akan membuatnya melampaui iterasi pertama. Anda hanya membandingkan dengan yang pertama value. Ngomong-ngomong, mengapa tidak menggunakan Anyseperti yang disarankan @Bob dan menyederhanakannya menjadireturn values.Any(value => Object.Equals(obj, value));
Konrad Morawski
1

"if (a == b atau c)" berfungsi di sebagian besar bahasa: jika a == b atau jika c tidak negatif, nol, atau nol.

Mengeluh bahwa itu sangat tidak tepat: Anda tidak harus menumpuk selusin hal menjadi sebuah persyaratan. Jika Anda perlu membandingkan satu nilai dengan angka sembarang dari nilai lainnya, maka buat subrutin.

Satanicpuppy
sumber
3
Bahasa apa yang membuat "sebagian besar"?
FrustratedWithFormsDesigner
1
@FrustratedWithFormsDesigner, well, jika cmengevaluasi ke boolean, maka hampir semua bahasa dapat menangani a == b || c:)
Brian S
@ Brian: Saya menganggap OP berarti sintaks literal if(a == b or c). Saya perlu istirahat, saya pikir ...: P
FrustratedWithFormsDesigner
@FrustratedWithFormsDesigner Lisp! ... ya? ... :)
Volker Siegel
3
Ini benar-benar merindukan inti pertanyaan. if (a == b or c)adalah pseudo-code untuk memeriksa apakah asama dengan b, atau asama dengan c. Itu tidak dimaksudkan untuk memeriksa bahwa citu bukan nol.
hvd
1

Biasanya, Anda ingin mempertahankan sintaks Anda seminimal mungkin dan sebaliknya membiarkan konstruksi seperti itu didefinisikan dalam bahasa itu sendiri.

Misalnya, di Haskell Anda dapat mengubah fungsi apa pun dengan dua atau lebih argumen menjadi operator infiks menggunakan backtick. Ini memungkinkan Anda untuk menulis:

if a `elem` [b, c] then ... else ...

di mana elemhanya fungsi normal mengambil dua argumen - nilai dan daftar nilai - dan memeriksa apakah yang pertama adalah elemen yang kedua.

Bagaimana jika Anda ingin menggunakan, andbukan or? Di Haskell, Anda bisa menggunakan yang berikut daripada menunggu vendor kompiler menerapkan fitur baru:

 if all (== a) [b, c] then ... else ...
Tobias Brandt
sumber
1
Mengapa orang ingin mempertahankan sintaks seminimal mungkin? Apa sebenarnya trade-off yang terjadi di sana? Jangan membuat proklamasi seperti itu tanpa mendukung argumen. ;)
Zeroth
1

Beberapa bahasa menawarkan ini - sampai batas tertentu.

Mungkin bukan sebagai contoh spesifik Anda , tetapi ambil contoh garis Python:

def minmax(min, max):
    def answer(value):
        return max > value > min
    return answer

inbounds = minmax(5, 15)
inbounds(7) ##returns True
inbounds(3) ##returns False
inbounds(18) ##returns False

Jadi, beberapa bahasa tidak masalah dengan beberapa perbandingan, selama Anda mengekspresikannya dengan benar.

Sayangnya, itu tidak berfungsi seperti yang Anda harapkan untuk perbandingan.

>>> def foo(a, b):
...     def answer(value):
...         return value == a or b
...     return answer
... 
>>> tester = foo(2, 4)
>>> tester(3)
4
>>> tester(2)
True
>>> tester(4)
4
>>> 

"Apa maksudmu mengembalikan True atau 4?" - Mempekerjakan setelah Anda

Salah satu solusi dalam hal ini, setidaknya dengan Python, adalah menggunakannya sedikit berbeda:

>>> def bar(a, b):
...     def ans(val):
...             return val == a or val == b
...     return ans
... 
>>> this = bar(4, 10)
>>> this(5)
False
>>> this(4)
True
>>> this(10)
True
>>> this(9)
False
>>> 

Sunting: Berikut ini juga akan melakukan sesuatu yang serupa, lagi dengan Python ...

>>> def bar(a, b):
...     def answer(val):
...             return val in (a, b)
...     return answer
... 
>>> this = bar(3, 5)
>>> this(3)
True
>>> this(4)
False
>>> this(5)
True
>>> 

Jadi, bahasa apa pun yang Anda gunakan, mungkin bukan karena Anda tidak bisa melakukannya, hanya saja Anda harus terlebih dahulu melihat lebih dekat bagaimana logika sebenarnya bekerja. Biasanya itu hanya masalah mengetahui apa yang sebenarnya Anda minta 'bahasa' untuk memberitahu Anda.


sumber
1

Metode indexOf, yang digunakan pada Array, yang dimiliki hampir semua bahasa, memungkinkan untuk membandingkan nilai dengan beberapa lainnya, jadi saya kira operator khusus tidak masuk akal.

Dalam javascript yang akan menulis:

if ( [b, c].indexOf(a) != -1 ) { ....  }
GameAlchemist
sumber
0

Anda bertanya mengapa kita tidak bisa melakukan ini: if(a == b or c)

Python melakukan ini dengan sangat efisien, pada kenyataannya, paling efisien dengan set:

if a in set([b, c]):
    then_do_this()

Untuk pengujian keanggotaan, 'set' memeriksa bahwa hash elemen adalah sama dan hanya kemudian membandingkan untuk kesetaraan, sehingga elemen, b dan c, harus dapat hashable, jika tidak daftar langsung membandingkan untuk kesetaraan:

if a in [b, c]:
    then_do_this()
Aaron Hall
sumber
0

Bahasa gaya APL memungkinkan Anda untuk membandingkan skalar dengan setiap elemen dalam vektor dalam satu operasi. Ini menghasilkan vektor Boolean. Sebagai contoh, saya ingin mempromosikan tanpa malu-malu apl kalkulator minimal saya, inca ( juru bahasa online ).

   a<5
5 
   b<4
4 
   c<5
5 
   a=b c
0 1 

Untuk mengurangi ini menjadi nilai tunggal, kita dapat melakukan inklusif atau dengan menjumlahkan dan memeriksa bukan nol.

   0!+/a=b c
1 
   c<6
6 
   0!+/a=b c
0

Jadi, seperti jawaban yang lain katakan, masalahnya adalah sintaksis. Hingga taraf tertentu, solusi sintaksis telah ditemukan, dengan biaya yang mahal untuk mempelajari paradigma array.

luser droog
sumber