'Zip' neden koleksiyonun sarkan kuyruğunu görmezden geliyor?


12

C # , Scala, Haskell, Lisp ve Python aynı zipdavranışa sahiptir: bir koleksiyon daha uzunsa, kuyruk sessizce göz ardı edilir.

Atılan bir istisna da olabilir, ancak bu yaklaşımı kullanan herhangi bir dil duymadım.

Bu beni şaşırtıyor. zipBu şekilde tasarlanma nedenini bilen var mı ? Sanırım yeni diller için yapılır, çünkü diğer diller bu şekilde yapar. Ama asıl sebep neydi?

Burada, birinin beğenip beğenmediği veya iyi ya da kötü bir yaklaşım olup olmadığı değil, olgusal, tarihi temelli bir soru soruyorum.

Güncelleme : Ne yapmam istendi, söyleyebilirim - bir dizini endekslemeye benzer şekilde bir istisna atın ("eski" diller her türlü sihri yaptı, sınırlar dizini, UB, diziyi genişletme, vb).


10
Bir işlevin sahip olduğu kuyruğu görmezden gelmezse, sonsuz dizileri kullanmak daha hantal olur. Özellikle sonsuz olmayan aralığın uzunluğunun elde edilmesi pahalı / kıvrık / imkansız ise.
Tekilleştirici

2
Bunun beklenmedik ve garip olduğunu düşünüyorsunuz. Açık ve gerçekten kaçınılmaz buluyorum. Ne olur sen sen eşitsiz uzunlukta koleksiyonları zip zaman ne istiyor?
Kilian Foth

@KilianFoth, bir istisna atıl.
greenoldman

@ Duplicalicator, güzel olan. Sessiz kuyruk damlası ile doğal olarak zipWithIndexdoğal sayı üreteci sağlayarak ifade edebilirsiniz . Şimdi, bilgi sadece eksik parçası - neydi o sebebi? :-) (btw. lütfen bir cevap olarak yorumunuzu tekrar gönderin, teşekkür ederim).
greenoldman

1
Python, bitmiş girdileri Nones ile etkili bir şekilde otomatik olarak eşleyen itertools.izip_longest'e sahiptir. Aslında zip kullandığımda sık sık zip üzerinden seçiyorum; artık herhangi bir seçimin arkasındaki nedenleri hatırlayamıyorum. Python, sık kullandığım @ greenoldman'ın durumu için enumerate () yöntemine sahip.
StarWeaver

Yanıtlar:


11

Neredeyse her zaman istediğiniz şeydir ve olmadığı zaman dolguyu kendiniz yapabilirsiniz.

Ana sorun, ilk başladığınızda uzunluğunu bilmediğiniz tembel anlambilimdir zip, bu yüzden başlangıçta bir istisna atamazsınız. İlk önce tüm ortak unsurları iade etmeniz, ardından çok yararlı olmayacak bir istisna atmanız gerekir.

Aynı zamanda bir stil meselesi. Zorunlu programcılar sınır koşullarını elle kontrol etmeye alışkındır. Fonksiyonel programcılar tasarımla başarısız olamayacak yapıları tercih ederler. İstisnalar oldukça nadirdir. Bir işlevin makul bir varsayılan değer döndürmesi için bir yol varsa, işlevsel programcılar bunu alacaktır. Kompostlanabilirlik kraldır.


Tarihi nedenleri soruyorum, ne yapabileceğimi değil. İkinci paragraf - yanılıyorsunuz, zipşu anda nasıl uygulandığına bir göz atın . Atma istisnası, "stop verimi" "atmak" olarak değiştirmektir. Üçüncü paragraf - sınırın dışına çıkmak için boş eleman döndürmek başarısız olamaz, ancak herhangi bir FP geliştiricinin iyi bir tasarım olduğunu oylayacağından şüpheliyim.
greenoldman

3
İkinci paragrafım tüm uygulamalar için geçerli değildir, sadece gerçekten tembel olanlar için geçerlidir. Eğer varsa zipbirlikte iki sonsuz diziler, sen başında boyutunu bilmiyorum. Üçüncü paragrafta makul bir temerrüt dedim . Bu durumda boş dönmek makul olmazken, kuyruğu düşürmek açıktır.
Karl Bielefeldt

Ah, sonunda neyi anlıyorum - tembel dilde istisna atmakla teknik bir değişiklik değil, tamamen davranış değişikliği, çünkü uygun olduğunda kuyruğu görmezden gelebildiğiniz için başlangıçta bir istisna atmanız gerekiyor.
greenoldman

3
+1 bu da harika bir cevaptır, "Fonksiyonel programcılar tasarımla başarısız olamayacak yapıları tercih ederler", bu da işlevsel programcıların verdiği tasarım kararlarının çoğunun arkasındaki en büyük motivasyonun ne olduğunu etkili bir şekilde ifade eder. Zorunlu programcıların "Anlat, sorma" yazan bir kuralı vardır, FP, mutlak son ana kadar sonuç kontrolü gerektirmeden talimatların sürekli olarak söylenmesine odaklanarak bunu N'inci dereceye çıkarır, bu nedenle ara adımları sağlamaya çalışırız başarısız olamaz , çünkü Kompostlanabilirlik kraldır. Çok güzel söyledi.
Jimmy Hoffa

12

Çünkü kuyruğu tamamlamak için belirgin bir yol yok. Nasıl yapılacağı konusunda herhangi bir seçim, açık olmayan bir kuyruğa neden olacaktır.

İşin püf noktası, en uzun listenizi beklediğiniz değerlerle eşleştirmek için en kısa listenizi açıkça uzatmaktır.

Zip bunu sizin için yaptıysa, sezgisel olarak hangi değerleri doldurduğunu bilemezdiniz. Listeyi çevrti mi? Mempty değerini tekrarladı mı? Türünüz için mempty değeri nedir?

Hangi zip'in kuyruğun uzatılacağı şekilde sezmek için kullanabileceği herhangi bir sonuç yoktur, bu yüzden yapılacak tek makul şey, tüketicinizin beklemeyebileceği kadar mevcut değerlerle çalışmaktır.


Ayrıca, iyi bilinen belirli semantiklere sahip çok spesifik bir iyi bilinen işleve atıfta bulunduğunuzu unutmayın. Ancak bu, benzer ancak biraz farklı bir işlev yapamayacağınız anlamına gelmez . Ortak bir işlev olduğu xiçin, yapmak istediğiniz amacınıza karar veremeyeceğiniz anlamına gelmez xve y.

Bu ve diğer birçok yaygın FP stili işlevinin yaygın olmasının nedenini hatırlasanız da, basit ve genelleştirilmiş olmalarıdır, böylece bunları kullanmak ve istediğiniz davranışı elde etmek için kodunuzu düzenleyebilirsiniz. Örneğin, C # 'da

IEnumerable<Tuple<T, U>> ZipDefaults(IEnumerable<T> first, IEnumerable<U> second)
{
    return first.Count() < second.Count()
        ? first.Concat(Enumerable.Repeat(default(T), second.Count() - first.Count())).Zip(second)
        : first.Zip(second.Concat(Enumerable.Repeat(default(U), first.Count() - second.count())))
}

Veya diğer basit şeyler. FP yaklaşımları değişiklikleri kolaylaştırır, çünkü parçaları yeniden kullanabileceğiniz gibi yukarıdaki gibi küçük uygulamalara sahip olmak, kendi değiştirilmiş şeylerin sürümlerini oluşturmak son derece basittir.


Tamam, ama sadece koleksiyonları diğerleriyle eşleşecek bir şey yapmaya zorladığınızda - koleksiyonun (dizi) indekslenmesi ile karşılaştırın. Eğer sınırların dışında dizin varsa genişletmek ve dizi düşünmeliyim düşünmeye başlayabilirsiniz? Ya da belki sessizce isteği görmezden gel. Ancak bir süredir ortak istisna atma fikri var. Burada aynı - eşleşen koleksiyonunuz yoksa, bir istisna atın. Neden bu yaklaşım benimsenmedi?
greenoldman

2
zipgenellikle sezgisel bir çözüm olan null'ları doldurabilir. Türü düşünün zip :: [a] -> [b] -> [(Maybe a, Maybe b)]. Kabul edilirse, sonuç türü biraz ^ H ^ H oldukça pratik değildir, ancak üzerine başka herhangi bir davranışın (kısa yol, istisna) kolayca uygulanmasına izin verecektir.
amon

1
@ amon: Bu hiç de sezgisel değil, saçma. Her argümanın null olarak kontrol edilmesini gerektirir.
DeadMG

4
@ amon her tür bir null değil, demek istediğim mempty, nesnelerin alanı doldurmak için null var, ama int ve diğer türler için böyle bir şey bulmasını ister misiniz? Elbette, C # default(T)tüm dillere sahip değildir , ancak C # için bile bu gerçekten açık bir davranış mıdır? Ben öyle düşünmüyorum
Jimmy Hoffa

1
@ amon Daha uzun listenin tüketilmeyen kısmını döndürmek daha yararlı olacaktır. Gereksinim duyduktan sonra eşit uzunlukta olup olmadıklarını kontrol etmek için bunu kullanabilirsiniz ve listeyi yeniden dolaşmadan tüketilmemiş kuyruğu ile tekrar fermuar veya bir şeyler yapabilirsiniz.
Doval
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.