Tür çıkarımı için tradeoff nedir?


29

Görünüşe göre, tüm yeni programlama dilleri veya en azından popüler olanları, tür çıkarımı kullanıyorlar. Javascript bile çeşitli uygulamalar olsa bile çeşit ve tip çıkarımı elde etti (Acscript, typescript vb.). Bana çok yakışıyor ama bence herhangi bir takas var mı, neden Java diyelim ya da eski iyi dillerin tür çıkarımı yok mu?

  • Go'da türünü belirtmeden bir değişken bildirirken (türsüz veya: = sözdizimi var kullanarak), değişkenin türü sağ taraftaki değerden çıkarılır.
  • D , dinamik diller gibi, fazlaca tür belirtmeden büyük kod parçalarının yazılmasını sağlar. Öte yandan, statik çıkarım, hem statik hem de dinamik dünyaların en iyisini veren türleri ve diğer kod özelliklerini çıkarır.
  • Rust tür çıkarım motoru oldukça akıllıdır. Başlatma sırasındaki r-değerinin tipine bakmaktan daha fazlasını yapar. Ayrıca değişkenin türünü anlamak için daha sonra nasıl kullanıldığını da gösterir.
  • Swift , uygun tipte çalışmak için tip çıkarımı kullanır. Tür çıkarımı, derleyicinin, yalnızca sağladığınız değerleri inceleyerek, kodunuzu derlerken belirli bir ifadenin türünü otomatik olarak algılamasını sağlar.

3
C # 'da, genel kurallar her zaman kullanmama vargerektiğini, çünkü okunabilirliği zedeleyebileceğini söylemektedir.
Mephy

5
“... ya da neden Java diyelim ya da eski iyi dillerin tür çıkarımı yok” Nedenleri muhtemelen tarihi; ML, Wikipedia’ya göre C’den 1 yıl sonra ortaya çıktı ve tip çıkarımı vardı. Java, C ++ geliştiricilere hitap etmeye çalışıyordu . C ++, C'nin bir uzantısı olarak başladı ve C'nin temel endişeleri, montaj üzerine taşınabilir bir sarıcı ve derlenmesi kolaydı. Neye mal olursa olsun, alt tiplemenin genel davada da tür çıkarımını belirsiz hale getirdiğini okudum.
Doval

3
@Doval Scala, alt tür kalıtımını destekleyen bir dil için, çıkarım türlerinde oldukça iyi bir iş çıkarmış gibi görünüyor. ML ailesi dillerinin hiçbiri kadar iyi değil, ancak dilin tasarımı göz önüne alındığında, muhtemelen isteyebileceğiniz kadar iyi.
KChaloux,

12
Tür indirimi (tek yönlü, C # varve C ++ gibi auto) ve tür çıkarımı (çift yönlü, Haskell gibi let) arasında bir ayrım yapmak faydalı olacaktır . Eski durumda, bir adın türü yalnızca ilklendiricisinden çıkarılabilir; kullanımları adın türünü izlemelidir. İkinci durumda, bir ismin türü kullanımlarından da çıkarılabilir - bu [], eleman türünden bağımsız olarak yalnızca boş bir dizi newEmptyMVariçin veya başvurudan bağımsız olarak yeni bir boş referans için yazabilmeniz açısından faydalıdır. yazın.
Jon Purdy

Tip çıkarımı, özellikle verimli bir şekilde uygulanması için inanılmaz derecede karmaşık olabilir. İnsanlar derleme karmaşıklıklarının daha karmaşık ifadelerden üstel patlamalara maruz kalmasını istemiyorlar. İlginç okuma: cocoawithlove.com/blog/2016/07/12/type-checker-issues.html
Alexander -

Yanıtlar:


43

Haskell'in tür sistemi tamamen çıkarılabilirdir (polimorfik özyinelemeyi bir kenara bırakarak, belirli dil uzantılarını ve korkunç monomorfizm kısıtlamasını bırakarak ), ancak programcılar hala ihtiyaç duymasalar bile kaynak kodunda tür ek açıklamaları sağlarlar. Niye ya?

  1. Tip açıklamaları dokümantasyon görevi görür . Bu özellikle Haskell'in ifade ettiği türler için geçerlidir. Bir işlevin adı ve türü göz önüne alındığında, özellikle işlevin parametrik olarak polimorfik olduğu durumlarda işlevin ne yaptığına ilişkin oldukça iyi bir tahmin yapabilirsiniz.
  2. Tip ek açıklamaları geliştirmeye neden olabilir . Bir fonksiyonun gövdesini yazmadan önce bir yazı imzası yazmak, teste dayalı bir gelişme gibidir. Tecrübelerime göre, bir Haskell fonksiyonunu derledikten sonra genellikle ilk defa çalışır. (Elbette, bu otomatik testlere olan ihtiyacı ortadan kaldırmaz!)
  3. Açık türler, varsayımlarınızı kontrol etmenize yardımcı olabilir . Zaten çalışan bazı kodları anlamaya çalışırken, doğru türde açıklamalar olduğuna inandığım şeyle sık sık biberlerim. Eğer kod hala derlenirse, anladığımı biliyorum. Olmazsa, hata mesajını okurum.
  4. İmzalar, polimorfik fonksiyonlar konusunda uzmanlaşmanıza izin verir . Çok nadiren, belirli işlevler polimorfik değilse, API daha anlamlı veya daha kullanışlıdır. Bir fonksiyona, çıkarımdan daha az genel bir tür verirseniz, derleyici şikayet etmez . Klasik örnek map :: (a -> b) -> [a] -> [b]. Daha genel formu ( fmap :: Functor f => (a -> b) -> f a -> f b) Functorsadece listeler için değil, tüm s için geçerlidir . Ancak mapyeni başlayanlar için anlaşılmasının daha kolay olacağı hissediyordu , bu yüzden abisinin yanında yaşıyor.

Genel olarak, statik olarak yazılan ancak çıkarılamayacak bir sistemin olumsuz yönleri, genel olarak statik yazmanın olumsuz yönleri ile aynıdır, bu site ve diğerleri hakkında iyi giyilen bir tartışma (Googling "statik yazım dezavantajları", yüzlerce kazanacaktır. alev savaş sayfalarının. Tabii ki, bahsedilen dezavantajların bazıları, çıkarılabilir bir sistemde daha az miktardaki tip açıklamalarla iyileştirilmektedir. Artı, tür çıkarımının kendine has avantajları vardır: delik kaynaklı geliştirme , tür çıkarım olmadan mümkün olmaz.

Java *, çok fazla türde ek açıklama gerektiren bir dilin can sıkıcı hale geldiğini, ancak çok azıyla yukarıda tarif ettiğim avantajları kaybettiğinizi kanıtlıyor. Vazgeçme türü çıkarımı olan diller, iki uç nokta arasında kabul edilebilir bir denge kurar.

* Bu büyük günah keçisi olan Java bile belirli bir miktarda yerel tip çıkarımı gerçekleştirir. Gibi bir ifadede Map<String, Integer> = new HashMap<>();, yapıcının genel türünü belirtmeniz gerekmez. Öte yandan, ML tarzı diller genel olarak küresel olarak çıkarılabilirdir.


2
Ama sen acemi değilsin;) Gerçekten "alınmadan" önce tür sınıfları ve türleri hakkında bir anlayışa sahip olmalısınız Functor. Listeler ve mapsezonluk olmayan Haskellers'e aşina olma ihtimaliniz daha yüksektir.
Benjamin Hodgson

1
C # 'nın varbir tür çıkarım örneği olduğunu düşünür müsünüz?
Benjamin Hodgson

1
Evet, C # 'ya varuygun bir örnek.
Doval

1
Site zaten bu tartışmayı çok uzun olarak işaretliyor, bu yüzden bu benim son cevabım olacak. Eskiden derleyici x; İkincisinde, belirlenecek tür yok, tüm türler bilinir ve yalnızca ifadenin anlamlı olup olmadığını kontrol etmeniz gerekir. Önemsiz örnekleri geçtiğinizde fark çok daha önemli hale gelir ve xbirden fazla yerde kullanılır; derleyici daha sonra xbelirlemek için kullanılan yerleri çapraz kontrol etmek zorundadır 1) xkodun onay yazacağı şekilde bir tip atamak mümkün mü? 2) Öyleyse, atayabileceğimiz en genel tür nedir?
Doval

1
new HashMap<>();Sözdiziminin yalnızca Java 7'ye eklendiğini ve Java 8'deki lambadaların oldukça fazla miktarda "gerçek" tür çıkarımı sağladığını unutmayın .
Michael Borgwardt

8

C #, derleme zamanında tür çıkarımı oluşur, bu nedenle çalışma zamanı maliyeti sıfırdır.

Tarz olarak, vartürü elle belirtmenin uygun olmadığı veya gereksiz olduğu durumlarda kullanılır. Linq böyle bir durumdur. Başka bir:

var s = new SomeReallyLongTypeNameWith<Several, Type, Parameters>(andFormal, parameters);

bu olmadan, gerçekten söylemekten ziyade, gerçekten uzun yazım adınızı (ve yazım parametrelerini) tekrar edersiniz var.

Açık olması kodun netliğini artırdığında türün gerçek adını kullanın.

Tip çıkarımının kullanılamadığı bazı durumlar vardır, örneğin yapım aşamasında değerleri belirlenmiş üye değişken bildirimleri veya gerçekten akıllıca çalışmasını istediğiniz yerler (Hackerrank'ın IDE'si değişkenin üyelerini akıllıca belirtmezseniz) .


16
"C #, derleme zamanında tür çıkarımı oluşur, bu nedenle çalışma zamanı maliyeti sıfırdır." Yazım çıkarımı derleme zamanında tanım gereği gerçekleşir, bu nedenle her dilde durum böyledir.
Doval,

Çok daha iyi.
Robert Harvey,

1
@Doval, bir çalışma zamanı maliyetine açıkça sahip olan JIT derlemesi sırasında tür çıkarımı yapmak mümkündür.
Jules

6
@Jules Eğer programı çalıştırmak kadar aldıysanız, o zaman zaten kontrol edilmiş; çıkarım yapacak hiçbir şey kalmadı. Bahsettiğiniz konuya genellikle tür çıkarımı denmez, ancak uygun terimin ne olduğundan emin değilim.
Doval

7

İyi soru!

  1. Tür açıkça açıklamalı olmadığından, bazen kodu okumayı zorlaştırabilir - bu da daha fazla hataya yol açabilir. Doğru kullanılması, kodu daha temiz ve daha okunaklı hale getirir . Eğer bir karamsar konum ve çoğu programcılar kötü (veya çoğu programcı çalışma olduğunu düşünüyorsanız olan kötü), bu net bir kayıp olacak.
  2. Tür çıkarım algoritması nispeten basit olsa da, ücretsiz değildir . Bu tür bir şey derleme süresini biraz artırır.
  3. Tür açıkça açıklamalı olmadığından, IDE'niz ne yapmaya çalıştığınızı tahmin edemez, bildirim sürecinde otomatik tamamlama ve benzeri yardımcılara zarar verebilir.
  4. İşlev aşırı yüklemeleriyle birlikte, zaman zaman tür çıkarım algoritmasının hangi yola gideceğine karar veremediği durumlarda çirkin döküm tarzı açıklamalara yol açabilirsiniz. (Bu, örneğin C # 'nın anonim işlev sözdizimi ile biraz olur).

Açık tuhaf açıklama olmadan tuhaflıklarını yapamayan daha ezoterik diller var. Şu ana kadar, bildiğim hiçbir şey yok; geçme dışında söyleyecek kadar yaygın / popüler / gelecek vaat eden.


1
Otomatik Tamamlama özelliği, tür çıkarımı hakkında bir şey vermiyor. Türün nasıl karar verdiğinin önemi yok, sadece türün neye sahip olduğu. Ve C # 'nın lambdaları ile ilgili problemler çıkarımla ilgisi yoktur, çünkü lambdalar polimorfiktir, ancak tip sistemi bununla baş edemez - ki bunun da çıkarımla ilgisi yoktur.
DeadMG

2
@deadmg - değişkeni bildirdikten sonra bir sorunu olmadığından emin olun, ancak değişken bildirgesini yazarken, sağ tarafın seçeneklerini bildirilen tür olmadığından daraltılamaz.
Telastyn

@deadmg - lambdalara gelince, ne demek istediğinizi tam olarak anlayamadım, ama işlerin nasıl yürüdüğüne dair fikrimden dolayı tamamen doğru olmadığından eminim. Bu kadar basit bir şey bile var foo = x => x;başarısız oluyor, çünkü dilin xburada çıkarsamaya ihtiyacı var ve devam edecek hiçbir şeyi yok. Lambdalar inşa edildiğinde, açıkça yazılan delegeler Func<int, int> foo = x => x, lambda'nın Func<int, int> foo = new Func<int, int>(x=>x);oluşturulmuş, açıkça yazılmış bir fonksiyon olarak yapıldığı CIL'e yerleştirilirler. Bana göre, xtürünün çıkarımı tür çıkarım türü ve parsel ...
Telastyn

3
@Telastyn Dilde devam edecek hiçbir şeyin olmadığı doğru değil. İfadeyi yazmak için gereken tüm bilgiler x => xlambda içinde bulunur - çevreleyen alandaki herhangi bir değişkeni ifade etmez. Aklı başında işlevsel dil doğru "her türlü onun tipi olduğu sonucuna ediyorum a, a -> a". DeadMG'nin söylemeye çalıştığı şey, C # 'nın tip sisteminin asıl tip özelliğinden yoksun olduğunu düşünüyorum; bu, herhangi bir ifade için en genel türü bulmaktan her zaman mümkün olduğu anlamına gelir. Yok edilmesi çok kolay bir özellik.
Doval

@Doval - enh ... C # 'da genel fonksiyon nesneleri gibi bir şey yoktur, ki bence aynı sorunlara yol açsa bile, ikinizin de konuştuğunuzdan tamamen farklı olduğunu düşünüyorum.
Telastyn

4

Bana çok yakışıyor ama bence herhangi bir takas var mı, neden Java diyelim ya da eski iyi dillerin tür çıkarımı yok mu?

Java burada kuraldan ziyade istisna olur. C ++ ("eski bir dil" olarak nitelendirdiğim :)) bile auto, C ++ 11 standardından bu yana anahtar kelimeyle tür çıkarımını destekliyor . Yalnızca değişken bildirimle değil, aynı zamanda bazı karmaşık şablon işlevlerinde özellikle kullanışlı olan işlev dönüş türü olarak da çalışır.

Örtük yazım ve yazım çıkarımının birçok iyi kullanım durumu vardır ve ayrıca gerçekten yapmamanız gereken bazı kullanım durumları da vardır. Bu bazen zevk meselesi ve aynı zamanda tartışma konusu.

Ancak kuşkusuz iyi kullanım durumlarının olduğu, herhangi bir dilin onu uygulayabilmesi için meşru bir sebep. Ayrıca, uygulanması zor bir özellik değildir, çalışma zamanı cezası yoktur ve derleme süresini önemli ölçüde etkilemez.

Geliştiriciye tip çıkarımı kullanma fırsatı vermenin gerçek bir dezavantajı görmüyorum.

Bazı cevaplayıcı nedenleri, açıkça yazmanın ne kadar iyi olduğunu ve kesinlikle haklı olduklarını söyledi. Ancak, örtük yazmayı desteklememek, bir dilin her zaman açık yazmayı zorladığı anlamına gelir.

Bir dil ne zaman gerçek beraberlik geri döndü Yani gelmez bununla doğru olmadığını kullanmaya geliştirici, hiçbir meşru bir neden olmadığı, devletler, çünkü örtük typeing desteklemektedir.


1

Bir Hindley-Milner tipi çıkarım sistemi ve Go tarzı tip çıkarım arasındaki temel ayrım bilgi akış yönüdür. HM'de, tür bilgisi birleşme aracılığıyla ileri ve geri akar; Git'te, bilgi girişi yalnızca ileriye doğru akar: yalnızca ileriye doğru ikame işlemlerini hesaplar.

HM tipi çıkarım, çok biçimli yazılan işlevsel dillerle iyi çalışan mükemmel bir yeniliktir, ancak Go yazarları muhtemelen çok fazla şey yapmaya çalıştığını iddia eder:

  1. Bilginin hem ileri hem de geri akması gerçeği, HM tipi çıkarımın çok yerel olmayan bir ilişki olduğu anlamına gelir; tür ek açıklamalarının yokluğunda, programınızdaki her kod satırı, tek bir kod satırının yazılmasına katkıda bulunabilir. Yalnızca ileriye doğru değiştirme işleminiz varsa, bir tür hatasının kaynağının, hatanızdan önce gelen kodda olması gerektiğini bilirsiniz; sonra gelen kod değil.

  2. HM tipi çıkarımda, kısıtlamaları düşünmeye meyilli: bir tür kullandığınızda, hangi olası türlere sahip olabileceğini kısıtlarsınız. Günün sonunda, tamamen kısıtlanmamış bırakılan bazı tip değişkenleri olabilir. HM tipi çıkarımın içgörüsü, bu tiplerin gerçekten önemli olmadığı ve bu yüzden polimorfik değişkenler haline getirildiğidir. Bununla birlikte, bu ekstra polimorfizm çeşitli nedenlerden dolayı istenmeyebilir. İlk olarak, bazılarının belirttiği gibi, bu ekstra polimorfizm istenmeyen olabilir: HM, sahte bir kod için sahte, polimorfik bir türün sonucuna varır ve daha sonra garip hatalara yol açar. İkincisi, bir tür polimorfik bırakıldığında, bunun çalışma zamanı davranışı için sonuçları olabilir. Örneğin, aşırı polimorfik bir ara sonuç, nedenini gösterme sebebidir. 'Haskell'de okumak' belirsiz olarak kabul edilir; başka bir örnek olarak,


2
Ne yazık ki, bu farklı bir soruya iyi bir cevap gibi görünüyor. OP, HM'ye karşı "Go-tarzı" değil, herhangi bir yazı tipi çıkarımı olmayan dillere karşı "Go-tarzı tip çıkarımı" hakkında sorular soruyor.
Ixrec

-2

Okunabilirliği incitiyor.

Karşılaştırmak

var stuff = someComplexFunction()

vs

List<BusinessObject> stuff = someComplexFunction()

Özellikle github'daki gibi bir IDE dışında okurken sorun var.


4
Bu, önceki 6
cevapta

"Karmaşık okunamaz" yerine uygun bir isim kullanırsanız, varokunabilirliği zedelemeden kullanılabilir. var objects = GetBusinessObjects();
Fabio

Tamam, ama sonra tip sistemini değişken isimlerine sızdırıyorsun. Macar notasyonu gibi. Yeniden yapılanmadan sonra, kodla eşleşmeyen isimlerle sonuçlanma olasılığınız daha yüksektir. Genel olarak, işlevsel stil sizi sınıfların sağladığı doğal isim alanı avantajlarını kaybetmeye zorlar. Böylece, square.area () yerine daha fazla squareArea () ile bitirdiniz.
miguel
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.