İşlev Dışı Ayarlarda Kapatma Uygulama Sorunları


18

Programlama dillerinde, kapaklar popüler ve sıklıkla istenen bir özelliktir. Wikipedia diyor ki (benimki vurgu):

Bilgisayar biliminde, kapatma (...), o işlevin yerel olmayan değişkenleri için bir referans ortamıyla birlikte bir işlevdir. Kapatma, bir işlevin anlık sözcük kapsamı dışındaki değişkenlere erişmesini sağlar.

Dolayısıyla, kapanış esasen değişkenleri kendi kapsamının dışında kullanabilen (anonim?) Bir işlev değeridir. Deneyimlerime göre, bu, tanım noktasında kapsamdaki değişkenlere erişebileceği anlamına gelir.

Uygulamada, kavram en azından fonksiyonel programlamanın dışında farklı görünüyor. Farklı diller farklı semantikleri uygular, hatta opinons savaşları var gibi görünüyor. Birçok programcı, anonim işlevlerden biraz daha fazlası olarak görerek, kapakların ne olduğunu bilmiyor gibi görünüyor.

Ayrıca, kapanışları uygularken büyük engeller var gibi görünüyor. En önemlisi, Java 7'nin bunları içermesi gerekiyordu, ancak özellik gelecekteki bir sürüme geri itildi.

Kapanışları gerçekleştirmek neden bu kadar zor (anlamak ve)? Bu çok geniş ve belirsiz bir soru, bu yüzden bu birbirine bağlı sorularla daha fazla odaklanmama izin verin:

  • Ortak semantik formalizmlerde kapanışları ifade etmede sorunlar var mı (küçük adım, büyük adım, ...)?
  • Mevcut tip sistemler kapaklar için uygun değil mi ve kolayca genişletilemiyor mu?
  • Kapakları geleneksel, yığın tabanlı yordam çevirisine uygun hale getirmek sorunlu mu?

Sorunun daha çok genel olarak prosedürel, nesne yönelimli ve senaryo dillerine ilişkin olduğunu unutmayın. Bildiğim kadarıyla, işlevsel dillerin herhangi bir sorunu yoktur.


İyi soru. Scala'da kapanışlar uygulandı ve Martin Odersky Java 1.5 derleyicisini yazdı, bu yüzden neden Java 7'de olmadıkları belli değil. (Daha sonra daha iyi bir cevap yazmaya çalışacağım.)
Dave Clarke

4
Lisp ve ML gibi saf olmayan işlevsel diller kapanışları iyi karşılar, bu yüzden sorunlu olmalarının asıl bir anlamsal nedeni olamaz.
Gilles 'SO- kötü olmayı bırak'

Maddeyi dahil ettim çünkü küçük adım semantiğinin kapanışlar için nasıl görünebileceğini hayal etmek için uğraşıyorum. Kendi içlerinde kapanmaların bir sorun olmaması çok iyi olabilir, ancak onları akıllarında tasarlanmamış bir dilde dahil etmek zordur.
Raphael

1
Pdfs.semanticscholar.org/73a2/… ' a bir göz atın - Lua yazarları bunu çok akıllı bir şekilde yaptılar ve kapanışları uygulamadaki genel sorunları tartıştılar
Bulat

Yanıtlar:


10

Sizi Funarg problem wikipedia sayfasına yönlendirebilir miyim? En azından derleyici insanlar kapatma uygulama sorununa bu şekilde başvuruyorlardı.

Dolayısıyla, kapanış esasen değişkenleri kendi kapsamının dışında kullanabilen (anonim?) Bir işlev değeridir. Deneyimlerime göre, bu, tanım noktasında kapsamdaki değişkenlere erişebileceği anlamına gelir.

Bu tanım mantıklı olsa da, geleneksel çalışma zamanı yığını tabanlı bir dilde birinci sınıf işlevlerin uygulanması sorununu tanımlamaya yardımcı olmaz. Uygulama sorunları söz konusu olduğunda, birinci sınıf işlevleri kabaca iki sınıfa ayrılabilir:

  • İşlevlerdeki yerel değişkenler işlev döndükten sonra asla kullanılmaz.
  • Yerel değişkenler işlev döndükten sonra kullanılabilir.

İlk durum (aşağı doğru funargs) uygulanması zor değildir ve Algol, C ve Pascal gibi daha eski prosedür dillerinde bile bulunabilir. İç içe işlevlere izin vermediğinden, Algol ve Pascal iç işlevlerin dış işlevin yığın değişkenlerine başvurmasına izin vermek için gerekli defter tutma işlemini gerçekleştirdiğinden sorunu çözer.

İkinci durumda (yukarı doğru funargs), aktivasyon kayıtlarının yığının dışında, yığına kaydedilmesini gerektirir. Bu, dil çalışma zamanı bir çöp toplayıcı içermediği sürece bellek kaynaklarını sızdırmanın çok kolay olduğu anlamına gelir. Hemen hemen her şey bugün toplanan çöp olsa da, bir tane istemek hala önemli bir tasarım kararıdır ve bir süre önce daha da öyleydi.


Java'nın belirli örneğine gelince, doğru hatırlıyorsam, asıl mesele aslında kapanışları uygulayamıyordu, ancak mevcut özelliklerle (anonim iç sınıflar gibi) gereksiz olmayan bir şekilde dile nasıl tanıtılacağı ve mevcut özelliklerle çelişmeyen (kontrol edilen istisnalar gibi - çözmek için önemsiz bir sorun olmayan ve çoğu insanın ilk başta düşünmediği bir sorun).

Ben de böyle gibi "sihirli" değişkenleri ile ne karar olarak uygulamaya birinci sınıf fonksiyonları daha az önemsiz hale başka şeyler, aklınıza gelebilecek bu , öz veya süper nasıl gibi mevcut denetim akışı operatörleri, etkileşime ve mola ve dönüş (yerel olmayan iadelere izin vermek istiyor muyuz?). Ancak sonuçta, birinci sınıf işlevlerin son zamanlarda popülaritesi, onlara sahip olmayan dillerin çoğunlukla tarihsel nedenlerden dolayı veya erken bazı önemli tasarım kararları nedeniyle bunu yaptığını göstermektedir.


1
Yukarı ve aşağı durumları birbirinden ayıran dilleri biliyor musunuz? .NET dillerinde, yalnızca aşağıya doğru bir işlev alması beklenen genel bir yöntem, genel tipte bir yapı ile birlikte bir byref (C #, bir " refparametre") gibi bir yapı alacak bir temsilci alabilir . Arayan, yapıdaki ilgili tüm değişkenleri kapsüle ettiyse, delege, yığın tahsisine ihtiyaç duyulmadan tamamen statik olabilir. Derleyiciler, bu tür yapılar için hoş bir sözdizimi yardımı sunmaz, ancak Çerçeve bunları destekleyebilir.
supercat

2
@supercat: Rust, bir iç işlevin öbeği kullanması gerekiyorsa derleme zamanında uygulamanızı sağlayan birden çok kapatma türüne sahiptir. Ancak bu, bir uygulamanın tüm bu ekstra türleri önemsemenize gerek kalmadan yığın ayırmalarından kaçınamayacağı anlamına gelmez. Bir derleyici işlev ömürlerini çıkarmaya çalışabilir veya değişkenleri yalnızca kesinlikle gerektiğinde yığınlara tembel olarak kaydetmek için çalışma zamanı denetimlerini kullanabilir ( ayrıntılar için Lua Evrimi belgesinin "sözcüksel kapsamı" bölümüne bakın)
hugomg

5

Kapakların C # 'da nasıl uygulandığını görebiliriz. C # derleyicisinin gerçekleştirdiği dönüşümlerin ölçeği, kapanışları uygulama yöntemlerinin oldukça fazla iş olduğunu açıkça ortaya koymaktadır. Kapakları uygulamanın daha kolay yolları olabilir, ancak C # derleyici ekibinin bunun farkında olacağını düşünüyorum.

Aşağıdaki sözde C # düşünün (C # belirli şeyler biraz kesip):

int x = 1;
function f = function() { x++; };
for (int i = 1; i < 10; i++) {
    f();
}
print x; // Should print 9

Derleyici bunu böyle bir şeye dönüştürür:

class FunctionStuff {
   int x;
   void theFunction() {
       x++;
   }
}

FunctionStuff theClosureObject = new FunctionStuff();
theClosureObject.x = 1;
for (int i = 1; i < 10; i++) {
    theClosureObject.theFunction();
}
print theClosureObject.x; // Should print 9

(gerçekte, f değişkeni yine de oluşturulacaktır, burada f bir 'temsilci' (= işlev işaretçisi), ancak bu temsilci hala theClosureObject nesnesiyle ilişkilidir - tanıdık olmayanlar için netlik sağlamak için bu bölümü dışarıda bıraktım C # ile)

Bu dönüşüm oldukça büyük ve zor: kapanışların içindeki kapanışları ve kapanışların C # dil özelliklerinin geri kalanıyla etkileşimini düşünün. Java 7'nin zaten birçok yeni özelliği olduğu için bu özelliğin Java için geri itildiğini hayal edebiliyorum.


Bunun nereye gittiğini görebiliyorum; birden çok kapama ve ana değişken erişiminin aynı değişkene sahip olması dağınık olacaktır.
Raphael

Dürüst olmak gerekirse, bu daha çok, kapakların uygulanması için mevcut OO çerçevesinin onlarla olan gerçek sorunlarından kaynaklanmasından kaynaklanmaktadır. Diğer diller sadece değişkenleri ayrı, yöntemsiz bir yapıda tahsis eder ve sonra birden fazla kapağın isterse paylaşmasına izin verir.
hugomg

@Raphael: Kapakların içindeki kapaklar hakkında ne düşünüyorsun? Bekle, onu ekleyeyim.
Alex ten Brink

5

Sorunuzun bir kısmını cevaplamak için. Morrisett ve Harper tarafından tanımlanan biçimcilik, kapaklar içeren daha üst düzey polimorfik dillerin büyük ve küçük adım semantiklerini kapsar. Bunlardan önce aradığınız anlambilim türlerini sağlayan makaleler var. Örneğin, SECD makinesine bakın . Bu semantiğe değiştirilebilir referanslar veya değişken yereller eklemek kolaydır. Bu semantiği sağlamada teknik bir sorun olduğunu görmüyorum.


Referans için teşekkürler! Hafif okuma için yapılmış gibi görünmüyor, ancak muhtemelen bir anlambilim kağıdından beklenmesi bekleniyor.
Raphael

1
@Raphael: Muhtemelen daha basit olanlar var. Bir şey bulmaya ve sana geri dönmeye çalışacağım. Her durumda, Şekil 8'de aradığınız anlambilim vardır.
Dave Clarke

Belki kaba bir genel bakış verebilirsiniz. cevabınızdaki merkezi fikirler?
Raphael

2
@Raphael. Belki de sizi programlama dilleri kursu için kullandığım ders notlarına yönlendirebilirim , bu da size hızlı bir giriş sağlar. Lütfen çalışma notları 8 ve 9'a bakınız.
Uday Reddy

1
Bu bağlantı ölü veya görünmez kimlik doğrulamasının arkasında görünüyor. ( cs.cmu.edu/afs/cs/user/rwh/public/www/home/papers/gcpoly/tr.pdf ). 403'ü yasaklıyorum.
Ben Fletcher
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.