Neden daha fazla dil bir değeri birden fazla değerle karşılaştıramaz? [kapalı]


10

Aşağıdakileri göz önünde bulundur:

if(a == b or c)

Çoğu dilde, bunun şu şekilde yazılması gerekir:

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

ki bu biraz hantaldır ve bilgiyi tekrarlar.

Yukarıdaki örnek sözdizimin biraz tıknaz olduğunu biliyorum, ama eminim fikri iletmenin daha iyi yolları var.

Neden daha fazla dil sunmuyor? Performans veya sözdizimi sorunları var mı?


6
SQL bunu sunar: nerede A IN (B, C)
thursdaysgeek

4
Bunu sunan ya da sahip olabilen dilleri sormuyordum, ama neden daha fazla dil sunmuyor? Performans veya sözdizimi sorunları var mı?
Sıfır

8
@ thursdaysgeek'in cevabını, çoğu dilde genelleştirmek için genellikle bunu küme sınırlamasıyla yaparsınız. (Veya daha kolaysa bir liste veya grup.) Aynı şekilde çalışır ve bazı zor sözdizimi sorunlarından kaçınır. Örneğinizden, "b veya c", "{b, c}" kümesi veya "veya" gibi bir işleç anlamına mı geliyor? ? Python'da "b veya c", doğruysa b değerini veya c değerini belirtir "
Rob

4
Temelde bu bir sözdizimi sorunudur. Elimizdeki sorun, "b veya c" ve "b veya c ile" arasındaki farkı netleştirmek için sezgisel bir yolu var.
YoungJohn

2
Özel durum için oldukça a == b or cacayip ve IMHO'yu bile iyi değil.

Yanıtlar:


24

Sözdizimi sorunu - sözdizimi gerektirmesidir.

Dilinizin sözdizimi ne olursa olsun, dili kullanan insanlar bunu öğrenmek zorundadır. Aksi takdirde kodu görme ve ne yaptığını bilmeme riski taşırlar. Bu nedenle, bir dilin birçok durumu temiz bir şekilde ele alan basit bir sözdizimi varsa, genellikle iyi bir şey olarak kabul edilir.

Özel örneğinizde, bir infix işleci (iki bağımsız değişken alan ancak yazılı bir işlev Argument1 Operator Argument2) almaya ve bunu birden çok bağımsız değişkene genişletmeye çalışıyorsunuz. Bu çok temiz bir şekilde çalışmaz, çünkü infix operatörlerinin bütün noktası, bir tane olduğu ölçüde, operatörü 2 argüman arasına koymaktır. Genişletmek, (Argument1 Operator Argument2 MagicallyClearSymbol Argument3...)fazla netlik katıyor gibi görünmüyor Equals(Arg1,Arg2,...). Infix, tipik olarak, insanların bildiği, alternatif bir sözdizimi için geçerli olmayacak matematik kurallarını taklit etmek için de kullanılır.

Ayrıştırıcının, ayrıştırma hızı üzerinde hafif bir etkisi olabilecek başka bir üretim kuralı veya iki dilbilgisi ile uğraşmak zorunda kalması dışında, fikrinizle ilişkili belirli bir performans sorunu olmayacaktır. Bu, yorumlanmış veya JIT derlenmiş bir dil için biraz fark yaratabilir, ancak büyük bir fark yaratmayabilir.

Fikirle ilgili en büyük sorun , bir dilde çok sayıda özel durum oluşturmanın kötü bir fikir olduğu yönündedir .


1
Bir kenara: Scala, rasgele sayıda argümana sahip infix operatörlerine sahiptir, çünkü infix operatörleri, a olmayan yöntem çağrılarıdır .. Yani onlar olarak yazılacaktı arg1 op (arg2, arg3). Tam olarak güzel değil, ama o dil bağlamında bazı yerlerde gerekli.
amon

peki ya if my_var in (a, b)o zaman? bu iş için doğru aracı kullanmakla ilgili bir soru değil mi?

Harika noktalar. Dil sözdizimi, dilin temel unsurları olmalıdır ve daha sonra bunun üzerine kütüphaneler oluşturursunuz. Eğer dil "yararlı" sözdizimsel şekerle çok fazla karışırsa, kullanımı zorlaşır. a == b or cDiğerleri isterken herkesin ihtiyacı yoktur a == b or c but not d. Yardımcı program işlevlerinin / kütüphanelerinin kurtarmaya geldiği yer IMO.
Allan

Belki de gerekli olan, bir yöntemin rastgele sayıda argüman içeren bir çağrının, sonuçların bir şekilde bir araya getirilmesiyle birden fazla çağrı olarak ele alınması gerektiğini belirleyebileceği bir araçtır. Eğer f().Equals(a,b,c); (var temp=f(); temp.Equals(a)||temp.Equals(b)||temp.Equals(c))sözdiziminin mükemmel olacağı şeklinde değerlendirilebilir , ancak bu şekilde değerlendirilmezse int[] arr = {a,b,c}; f().Equals(arr);, özellikle her çağrı için yeni bir dizi oluşturulması gerekiyorsa.
supercat

6

Çünkü bu bir problem değildir ve çözmesi temelde sıfır fayda getirir, ancak uygulanması sıfır olmayan maliyet getirir.

Mevcut aralık tabanlı işlevler ve hemen hemen her dilin sunduğu gibi, bu durumda a == b || a == ckesilmeyecek bir boyuta ölçeklenirse mükemmel bir şekilde çalışabilir .


2
+1, ancak bence cevap, pratikte her dilin [sunduğu] mevcut mevcut aralık tabanlı işlevlerden biri veya iki tanesi gösterilerek geliştirilebileceğini düşünüyorum, bu yüzden bu alternatif daha açık olacaktır.
Avner Shahar-Kashtan

"Temel olarak sıfır fayda getirdiğini, ancak uygulanmasının sıfır olmayan maliyet getirdiğini" kanıtlayabilir misiniz?
Darek Nędza

3
@ DarekNędza İkinci yarı çekişmeli olmamalı: Her özellik düşünülmeli, uygulanmalı, test edilmeli, belgelenmeli ve desteklenmelidir. Bu adımların hiçbiri makul bir metrik altında ücretsiz değildir (insanların zamanı, fırsat maliyeti, karmaşıklık, üzerinde çalışmak için para ödenmişse parasal maliyet vb.).

@ AvnerShahar-Kashtan Kabul etti - bana göre, java, sh veya zsh'a nasıl bakacağı belli değil mi? Tamam, 'modern' bir dil ima etmiş olabilir. Groovy?
Volker Siegel

PHP'de böyle görünecektir in_array($a, [$b, $c, $d, $e, $f]). : P
cHao

6

Bazı diller böyle özelliklere sahiptir. Örneğin Perl6'da iki değerin “üst üste binmesi” olan Kavşakları kullanabiliriz :

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

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

Kavşaklar, skaler işlemlerin bazı dillerdeki koleksiyonlara dağıtılmasına benzer şekilde, bir dizi veri üzerindeki işlemleri oldukça kısa bir şekilde ifade etmemizi sağlar. Örneğin, numpy ile Python kullanarak karşılaştırma tüm değerlere dağıtılabilir:

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

Ancak, bu yalnızca belirli ilkel tipler için geçerlidir.

Kavşaklar neden sorunlu? Bir kavşaktaki işlemler içerilen değerler üzerinde dağıtıldığı için, kavşak nesnesinin kendisi yöntem çağrıları için bir proxy gibi davranır - ördek yazmanın yanı sıra birkaç tür sistem işleyebilir.

Bu tür kavşaklara yalnızca karşılaştırma işleçleri etrafında özel sözdizimi olarak izin veriliyorsa, tür sistem sorunlarından kaçınılabilir . Ancak bu durumda, herhangi bir aklı diline eklenecek yeterli değer katmayacak kadar sınırlıdırlar. Aynı davranış, set işlemleri kullanılarak veya tüm karşılaştırmaları elle heceleyerek ifade edilebilir ve çoğu dil, zaten mükemmel bir çözüm varsa gereksiz sözdizimi eklemeye inanmaz.


Bu özel numpy örneği daha net olarak yeniden yazılabilir 2 in [1, 2, 3]. Öte yandan, numpy bir .all()ya da bir şeye sahipse , eşdeğer düz python neredeyse özlü değildir.
Izkata

@Izkata Özellikle set operasyonlarını kullanmadım. Örneğim ==operatörü kullanırken, <bunun yerine de kullanabiliriz - şu inan nerede ? Kavşak üzerinde operasyonlar tüm üyeleri üzerinde dağıtmak çünkü Eklemler, ayarlanan üyelik testlerinden daha geneldir - (x|y).fooolduğu x.foo|y.foo, kavşak nihayet tek değere boşalana kadar. Sağlanan NumPy kodu, ilkel tipler varsayarak Perl6 kavşaklarının tam olarak eşdeğer ancak daha ayrıntılı bir çevirisini gösterir.
amon

2

Makro içeren dillerde, zaten orada değilse böyle bir şey eklemek kolaydır. Raketi düşünün

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

Meta programlama olmadan diğer dillerde, belki de set / list üyelik kontrolü olarak yeniden düzenleyebilirsiniz:

if a ∈ {b, c}

2
İlk ikisi tüm argümanların eşit olup olmadığını kontrol eder; OP, ilk argümanın aşağıdakilerden herhangi birine eşit olup olmadığını kontrol etmek ister. İlginçtir ki, gösterdiğiniz üçüncü snippet buna saygı duyar.

@delnan Üzgünüm işleri yanlış anladım. Ben düzenledim.
Phil

2

Bazı (popüler) dillerde ==operatör geçişli değildir. JavaScript Mesela 0hem eşittir ''ve '0'o zaman, ama ''ve '0'birbirinden için eşit değildir. PHP bu tür tuhaflık daha.

Bunun a == b == cbaşka bir belirsizlik katacağı anlamına gelir , çünkü (a == b) & (a == c)veya olarak yorumlanıp yorumlanmadığına bağlı olarak farklı bir sonuç verebilir (a == b) & (a == c) & (b == c).


2

Çoğu dilde, bu bir Inişlev yazarak önemsiz bir şekilde başarılmalıdır , o zaman onu neden gerçek dilin bir parçası yapalım?

Linq, örneğin vardır Contains().

Pekala, tüm akranlarınız için C # uygulamam:

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;
}

Bu, OP'nin kodu olarak bir demet olarak değil, çalışma zamanı değer aralığında çalışır.
DeadMG

Görünüşe göre, sadece kolay olması, yapılmaması gerektiği anlamına gelmez. Yapım ... düşünün. Neden her zaman bu temel işlevsellik ve algoritma parçalarını tekrar tekrar tekrar tekrar yazmak zorunda kalıyoruz?
Sıfır

5
@ Sıfır belki de aynı şeyi tekrar tekrar yazıyorsunuz, ancak diğerleri bunun yerine kendi dilleri tarafından sunulan soyutlama mekanizmalarını kullanma eğilimindedir. Yazmakta kendini görürseniz a == b || a == cbirden çok kez, belki de zamanıequals_any(a, {b, c})
amon

"İçerir" uygulaması, if (a > (b or c))ve gibi şeyleri kapsayacak şekilde kolayca genişletilmez if (a mod (b or c) == 2).
55'te tobyink

1
Birisi saçmalık mı dedi? :) Bu bir foreach döngüleri, bu yüzden ideğişken yok . Uzun bir gün geçirdik sonra :) hem koyarak Çünkü Ve genel olarak yazılmış gibi görünüyor return trueve return falsedöngü içinde burada hiç birinci yineleme ötesinde yapacaktır yolu yok demektir. Sadece ilkiyle karşılaştırıyorsunuz value. Bu arada, neden Any@Bob'un önerdiği gibi kullanmıyorsunuz ve basitleştiriyorsunuzreturn values.Any(value => Object.Equals(obj, value));
Konrad Morawski

1

"if (a == b veya c)" çoğu dilde çalışır: a == b veya c negatif, null veya sıfır değilse.

Ayrıntılı olduğundan şikayet etmek, noktayı kaçırıyor: bir düzine şeyi koşullu bir şekilde kazmamalısınız. Bir değeri rastgele başka bir değerle karşılaştırmanız gerekiyorsa, bir alt yordam oluşturun.


3
Hangi diller "en" oluşur?
SinirliWithFormsDesigner

1
@FrustratedWithFormsDesigner, cbir boolean olarak değerlendirilirse, hemen hemen her dil işleyebilir a == b || c:)
Brian S

@BrianS: OP'nin gerçek sözdizimi anlamına geldiğini varsaydım if(a == b or c). Bir ara
SinirliWithFormsDesigner

@FrustratedWithFormsDesigner Lisp! ... ha? ... :)
Volker Siegel

3
Bu gerçekten sorunun anlamını kaçırıyor. if (a == b or c)kontrol etmek amacıyla sözde kodu aisimli e eşit bya da aeşittir c. cSıfır olmadığını kontrol etmek anlamına gelmez .
hvd

1

Genellikle, söz diziminizi minimumda tutmak ve bunun yerine bu tür yapıların dilin kendisinde tanımlanmasına izin vermek istersiniz.

Örneğin, Haskell'de iki veya daha fazla bağımsız değişkeni olan herhangi bir işlevi, ters işaretler kullanarak bir infix operatörüne dönüştürebilirsiniz. Bu şunları yazmanıza izin verir:

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

Burada elem, iki değer alan normal bir işlevdir - bir değer ve bir değer listesi - ve ilki ikinci öğenin bir öğesi olup olmadığını kontrol eder.

Bunun andyerine kullanmak isterseniz ne olur or? Haskell'de, derleyici satıcısının yeni bir özellik uygulamasını beklemek yerine aşağıdakileri kullanabilirsiniz:

 if all (== a) [b, c] then ... else ...

1
Neden sözdizimini minimumda tutmak istesin ki? Ödünç alma işlemi tam olarak ne oluyor? Argümanları desteklemeden böyle açıklamalar yapmayın. ;)
Zeroth

1

Bazı diller bunu bir ölçüde sunmaktadır.

Belki belirli bir örnek olarak değil , örneğin bir Python satırı alın:

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

Bu nedenle, bazı diller doğru şekilde ifade ettiğiniz sürece birden fazla karşılaştırmayla iyidir.

Ne yazık ki, karşılaştırmalar için beklediğiniz gibi çalışmıyor.

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

"Ne demek True ya da 4 döndürür?" - senden sonra işe alma

Bu durumda, en azından Python ile bir çözüm, onu biraz farklı kullanmaktır:

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

DÜZENLEME: Aşağıdaki, yine Python'da benzer bir şey yapardı ...

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

Kullandığınız hangisi dil Yani, onunla bu olmayabilir olamaz öncelikle mantık aslında nasıl çalıştığına yakından bakmak gerekir sadece, bunu. Tipik olarak, bu dili size ne söylemesini gerçekten istediğini bilmekle ilgilidir.


1

Tamamen tüm dillerin sahip olduğu bir Array'de kullanılan indexOf yöntemi, bir değeri başkalarıyla karşılaştırmaya izin verir, bu nedenle özel bir işleç çok mantıklı değildir.

Javascript'te şöyle yazar:

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

0

Bunu neden yapamayacağımızı soruyorsun: if(a == b or c)

Python bunu çok verimli, aslında en verimli şekilde yapar set:

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

Üyelik testi için 'set' öğenin karmalarının aynı olup olmadığını denetler ve ancak o zaman eşitlikle karşılaştırır, bu nedenle b ve c öğelerinin yıkanabilir olması gerekir, aksi takdirde bir liste doğrudan eşitlikle karşılaştırılır:

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

0

APL tarzı diller, tek bir işlemde bir vektördeki her bir öğe ile bir skaler karşılaştırmanıza izin verir. Bu bir Boolean vektörü üretir. Bir örnek olarak, minimal özellikli apl hesap makinemi utanmazca tanıtmak istiyorum, inca ( çevrimiçi yorumlayıcı ).

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

Bunu tek bir değere düşürmek için, kapsayıcı veya sıfır olmayanları toplayıp kontrol ederek yapabiliriz.

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

Diğer cevapların dediği gibi, konu sözdizimidir. Bir dereceye kadar, sözdizimi çözümler gelmiş dizi paradigmasını öğrenme belki ağır maliyetle bulundu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.