Tüm fonksiyonel diller çöp toplama kullanıyor mu?


32

Yığın anlambiliminin kullanılmasına izin veren işlevsel bir dil var mı - kapsamın sonunda otomatik deterministik yıkım?


Deterministik yıkım, yalnızca yan etkilerde yardımcı olabilir. Saf işlevsel programlama bağlamında , bu yalnızca (monadik) eylemlerin her zaman bir dizinin sonunda gerçekleştirilmesini sağlamak anlamına gelir. Bunun yanında, çöp toplama gerektirmeyen fonksiyonel bir birleştirici dil yazmak kolaydır .
Jon Purdy

Soru bağlamında ilgileniyorum, kişinin teftişle ne ilgisi var?
mattnz

1
Çöp toplama olmadan işlevsel bir dilde, değişken veri yapılarının yapısal paylaşımının nasıl mümkün olduğunu anlamıyorum. Böyle bir dil oluşturmak mümkün olabilir, ancak kullanacağım bir dil değil.
dan_waterworth 12:12

Rust, yaygın olarak 'işlevsel' olarak tanımlanan bir çok özelliğe sahiptir (en azından, işlevsel olmayan dilimler olarak sıkça aranır). Ne eksik olduğunu merak ediyorum. Varsayılan olarak İmmut, kapanmalar, fonksiyon geçişi, ilkeli aşırı yükleme, ADT'ler (henüz GADT yok), desen eşleştirme, hepsi GC'siz. Başka?
Noein

Yanıtlar:


10

Bildiğim kadarıyla işlevsel bir programlama uzmanı olmasam da.

Prensipte oldukça zor görünüyor, çünkü işlevlerden döndürülen değerler, aynı işlev içinde oluşturulan (yığında) diğer değerlere referanslar içerebilir veya bir parametre olarak kolayca iletilmiş veya iletilen bir şey tarafından başvurulan olabilir parametre olarak. C'de, bu sorun, programcı işleri doğru yapmazsa, sarkan işaretçilerin (veya daha kesin olarak tanımsız davranış) oluşmasına izin verilerek ele alınmaktadır. Bu, fonksiyonel dil tasarımcılarının onayladığı bir çözüm değil.

Yine de potansiyel çözümler var. Bir fikir, değerin kullanım ömrünü, değer referansının yanı sıra, değerin türünün bir parçası haline getirmek ve yığın tarafından ayrılan değerlerin geri döndürülmesini veya geri döndürülen bir şey tarafından referans alınmasını engelleyen tür tabanlı kuralları tanımlamaktır. işlevi. Etkilerin üzerinden çalışmadım, ama korkunç olacağını düşünüyorum.

Monadik kod için, (aslında veya neredeyse) monadik olan ve otomatik olarak determinist olarak tahrip edilmiş bir IORef türünü verebilecek başka bir çözüm var. İlke "iç içe geçme" eylemlerini tanımlamaktır. Birleştirildiğinde (bir ilişkisel işleç kullanarak) bunlar iç içe geçmiş bir kontrol akışını tanımlar - bence "XML elemanı", dış başlangıç ​​ve bitiş etiketi çiftini sağlayan değerlerin en soluyla. Bu "XML etiketleri", başka bir soyutlama düzeyindeki monadik eylemlerin sırasını tanımlamaktadır.

Bir noktada (birleştirici kompozisyon zincirinin sağ tarafında) yuvalamayı sonlandırmak için bir tür sonlandırıcıya ihtiyacınız vardır - ortadaki deliği dolduracak bir şey. Bir sonlandırıcıya duyulan ihtiyaç, yuvalama kompozisyonu işlecinin monadik olmadığı anlamına gelmesidir, ancak yine de, ayrıntılarla çalışmadığımdan tam olarak emin değilim. Sonlandırıcının tüm uygulanması, bir yerleştirme eylemini etkili bir şekilde oluşturulmuş normal monadik eyleme dönüştürmek olduğundan, belki de değil - yerleştirme bileşimi işlecini mutlaka etkilemez.

Bu özel eylemlerin birçoğu boş bir "bitiş etiketi" basamağına sahip olacak ve "başlangıç ​​etiketi" basamağını bazı basit monadik eylemlerle eşleştirecektir. Ancak bazıları değişken bildirimleri temsil eder. Bunlar kurucu ile başlama etiketini ve yıkıcı ile bitiş etiketini temsil eder. Demek böyle bir şey alıyorsun ...

act = terminate ((def-var "hello" ) >>>= \h ->
                 (def-var " world") >>>= \w ->
                 (use-val ((get h) ++ (get w)))
                )

Aşağıdaki yürütme sırasına sahip bir monadik bileşime çeviri yapmak, her bir etiket (eleman değil) normal bir monadik eylem haline gelir ...

<def-var val="hello">  --  construction
  <def-var val=" world>  --  construction
    <use-val ...>
      <terminator/>
    </use-val>  --  do nothing
  </def-val>  --  destruction
</def-val>  --  destruction

Bunun gibi kurallar, C ++ tarzı RAII'nin uygulanmasına izin verebilir. IORef'e benzeyen referanslar, normal IORef'lerin monaddan neden kaçamayacağına benzer nedenler nedeniyle, kapsamdan kaçamazlar - ilişkisel kompozisyonun kuralları referansın kaçmasına imkan vermez.

EDIT - neredeyse söylemeyi unuttum - burada emin olamadığım kesin bir alan var. Bir dış değişkenin bir iç değişkene referans verememesini sağlamak önemlidir, bu nedenle bu IORef benzeri referanslarla yapabilecekleriniz kısıtlamaları olmalıdır. Yine, tüm detayları üzerinde çalışmadım.

Bu nedenle, inşaat, örneğin yıkımın kapandığı bir dosyayı açabilir. İnşaat, yıkımın kapandığı bir soket açabilir. Temel olarak, C ++ 'da olduğu gibi, değişkenler kaynak yöneticisi olur. Ancak C ++ 'dan farklı olarak, otomatik olarak tahrip edilemeyen yığınla tahsis edilmiş nesneler yoktur.

Bu yapı RAII'yi desteklese de, hala bir çöp toplayıcısına ihtiyacınız var. Yuvalama eylemi belleği ayırabilir ve boşaltabilse de, kaynak olarak kabul etse de, bu bellek yığını içindeki ve başka yerlerdeki (potansiyel olarak paylaşılan) işlevsel değerlere ilişkin tüm referanslar hala vardır. Hafızanın yığın üzerinde basit bir şekilde tahsis edilebildiği ve bir yığın ücretsiz ihtiyacından kaçınılabileceği düşünüldüğünde, asıl önemi (eğer varsa) diğer kaynak yönetimi türleri içindir.

Öyleyse, bu başarının amacı RAII tarzı kaynak yönetimini bellek yönetiminden ayırmak, en azından RAII'nin basit yuvalama kapsamına dayanması durumunda. Bellek yönetimi için hala bir çöp toplayıcısına ihtiyacınız var, ancak diğer kaynakların güvenli ve zamanında otomatik olarak deterministik bir şekilde temizlenmesini sağlıyorsunuz.


GC'nin neden tüm işlevsel dillerde gerekli olduğunu göremiyorum . C ++ stilli bir RAII çerçeveniz varsa, derleyici bu mekanizmayı da kullanabilir. Paylaşılan değerler RAII çerçeveleri için sorun değil (bakınız C ++ 'lar shared_ptr<>), yine de deterministik yıkımı sürdürüyorsunuz. RAII için zor olan bir şey döngüsel referanslardır; Sahiplik grafiği bir Yönlendirilmiş Asiklik Grafik ise RAII temiz çalışır.
MS 12.06

Mesele şu ki, işlevsel programlama stili pratikte kapaklar / lambdas / anonim işlevler üzerine inşa edilmiştir. GC olmadan, kapanışlarınızı kullanmak için aynı özgürlüğe sahip değilsinizdir, böylece diliniz çok daha az işlevsel hale gelir.
fırtına

@torptorm - C ++ 'da lambdalar var (C ++ 11'den itibaren) ancak standart çöp toplayıcı yok. Lambdalar çevrelerini de bir kapanışta taşırlar - ve bu ortamdaki elementler, göstergelerin değerine göre geçme ihtimalinin yanı sıra referans olarak geçilebilir. Ancak ikinci paragrafımda yazdığım gibi, C ++ işaretçilerin sarkma ihtimaline izin veriyor - bunun asla olmaması için programlayıcılar (derleyiciler veya çalışma ortamı ortamları yerine) sorumluluğu.
Steve314

@ MSalters - hiç bir referans döngüsü oluşturulamamasının sağlanmasında maliyetler vardır. Bu nedenle, dili bu kısıtlamadan sorumlu kılmak en azından önemsizdir. Bir işaretçiye atama muhtemelen sürekli olmayan bir işlem haline gelir. Yine de bazı durumlarda en iyi seçenek olabilir. Çöp toplama işlemi bu sorunu farklı maliyetlerle önler. Programcıyı sorumlu kılmak başka bir şeydir. Sarkan işaretçilerin zorunlu ama işlevsel dillerde iyi olmamasının güçlü bir nedeni yok, ancak yine de pointer-sarkan-Haskell yazmayı önermiyorum.
Steve314

Manuel bellek yönetiminin, Lisp veya Haskell kapanışları gibi C ++ 11 kapanışlarını kullanma özgürlüğünüzün olmadığı anlamına gelir. (Ben dili programlama fonksiyonel sistemler yazmak istiyorum ben aslında oldukça ... Bu değişimin detaylarını anlamada ilgilenen am)
comingstorm

3

C ++ 'ın işlevsel bir dil olduğunu düşünürseniz (lambdas'ı vardır), o zaman çöp toplama kullanılmayan bir dilin örneğidir.


8
C ++ 'ı işlevsel bir dil olarak düşünmüyorsanız (IMHO öyle değildir, onunla işlevsel bir program yazabilmenize rağmen, bununla birlikte bazı son derece işlevsel olmayan (işleyen ....) programlar da yazabilirsiniz)
mattnz

@ mattnz O zaman cevap geçerli değildir sanırım. Diğer dillerde ne olduğundan emin değilim (örneğin haskel gibi)
BЈовић

9
C ++ 'ın işlevsel olduğunu söylemek Perl'in Nesne Yönelimli olduğunu söylemek gibidir ...
Dinamik

En azından c ++ derleyicileri yan etkileri kontrol edebilir. (const aracılığıyla)
tp1

@ tp1 - (1) Umarım bu, kimin dilinin en iyisi olduğuna gerilemez ve (2) bu doğru değildir. İlk olarak, gerçekten önemli olan etkiler çoğunlukla G / Ç'dir. İkincisi, değiştirilebilir hafıza üzerindeki etkiler için bile const bunları engellemez. Tip sistemini altüst etme ihtimalinin olmadığını varsaysanız bile (genellikle C ++ 'da mantıklı), mantıksal bir sorun ve "mutable" C ++ anahtar sözcüğü söz konusudur. Temelde, const rağmen hala mutasyonlar olabilir. Sonucun hala "mantıksal olarak" aynı olmasını, ancak mutlaka aynı yanıtı vermemesini beklemelisiniz.
Steve314 11.03.2012

2

Sorunun biraz kötü tanımlandığını söylemeliyim çünkü standart bir "fonksiyonel dil" koleksiyonu olduğunu varsayıyor. Hemen hemen her programlama dili, bir miktar işlevsel programlamayı destekler. Ve hemen hemen her programlama dili bir miktar zorunlu programlamayı destekler. Kültürel önyargılar ve popüler dogmanın rehberliğinde, hangisinin işlevsel bir dil olduğunu ve zorunlu bir dil olduğunu söyleme çizgisi nerede çiziliyor?

Soruyu ifade etmenin daha iyi bir yolu, "yığın destekli bellekte fonksiyonel programlamayı desteklemek mümkün mü" olacaktır. Cevap, daha önce de belirtildiği gibi çok zor. İşlevsel programlama stili, bir yığın bellek gerektiren özyinelemeli veri yapılarının tahsis edilmesini teşvik eder (çöp toplanır veya referans sayılır). Ancak, derleyicinin yığını yığın tahsisine benzer şekilde otomatik olarak tahsis edilip tahsis edilebilecek büyük bloklara bölebileceği bölge bazlı bellek analizi adı verilen oldukça karmaşık bir derleyici analiz tekniği vardır . Wikipedia sayfası, hem "işlevsel" hem de "zorunlu" diller için tekniğin çeşitli uygulamalarını listeler.


1
IMO referans sayma olan çöp toplama ve bir yığın sahip olanlar sadece seçenekler zaten olduğu anlamına gelmez. C mallocs ve bir yığın kullanarak mfrees, ancak (standart) çöp toplayıcı yok ve sadece bunu yapmak için kod yazarsanız referans sayar. C ++ hemen hemen aynıdır - (standart olarak, C ++ 11'de), referans sayımı yerleşik akıllı işaretçilere sahiptir, ancak yine de gerçekten el ile yeni şeyler yapabilir ve silebilirsiniz.
Steve314

Referans sayımının çöp toplama olmadığını iddia etmenin yaygın bir nedeni, referans döngülerini toplamamasıdır. Bu kesinlikle basit uygulamalar için geçerlidir (muhtemelen C ++ akıllı işaretçiler dahil - kontrol etmedim) ama bu her zaman böyle değildir. En az bir Java sanal makinesi (IBM, IIRC) çöp toplama işleminin temeli olarak referans saymayı kullandı.
Steve314
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.