λ-hesabı: Fonksiyonların hafıza gösterimlerinde en etkili olan nedir?


9

Klasik kodlanmış (birleştirici / C) veri yapıları ile kodlanmış (Kilise / Scott) fonksiyonlarının performansını karşılaştırmak istiyorum.

Ama bunu yapmadan önce, bellekte işlev gösteriminin ne kadar verimli olduğunu / olabileceğini bilmeliyim. Fonksiyon elbette kısmen uygulanabilir (aka kapatma).

Hem geçerli kodlama algoritması popüler fonksiyonel diller (Haskell, ML) kullanımı hem de elde edilebilecek en verimli dil ile ilgileniyorum .


Ek noktası: orada harita doğal tam sayı tamsayıları kodlanan işlevini şekilde kodlama (mi short, intvb C). Hatta mümkün mü?


Performansa göre verime değer veriyorum. Başka bir deyişle, kodlama ne kadar verimli olursa fonksiyonel veri yapıları ile hesaplama performansını o kadar az etkiler.


Tüm Google girişimlerim başarısız oldu, belki de doğru anahtar kelimeleri bilmiyorum.
Ford O.

"Verimli" ile ne demek istediğinizi netleştirmek için soruyu düzenleyebilir misiniz? Ne için verimli? Verimli bir veri yapısı istediğinizde, veri yapısı seçimini etkileyeceğinden, veri yapısı üzerinde hangi işlemleri gerçekleştirmek istediğinizi belirtmeniz gerekir. Yoksa kodlamanın mümkün olduğunca az yer kapladığını mı söylüyorsunuz?
DW

1
Bu oldukça geniştir. Lambda hesabı için verimli bir şekilde yürütmeyi amaçlayan birçok soyut makine var (bkz. Örneğin SECD, CAM, Krivine, STG). Bunun da ötesinde, daha fazla sorun yaratan Church / Scott kodlu verileri dikkate almanız gerekir. Örneğin Kilise kodlu listelerde kuyruk operasyonu O (1) yerine O (n) olmalıdır. Bir yerde O (1) baş ve kuyruk operasyonları ile Sistem F listeler için bir kodlama varlığını hala açık bir sorun olduğunu düşünüyorum.
chi

@DW Performans / genel gider hakkında konuşuyorum. Örneğin kilisenin listesi ve Haskell'in listesi üzerinde etkili kodlama eşlemesi ile aynı zamanı almalıdır.
Ford O.

Hangi işlem (ler) için performans? Fonksiyonlarla ne yapmak istiyorsunuz? Bu işlevleri bir değer üzerinde değerlendirmek ister misiniz? Bir kez veya aynı işlevi birçok değer üzerinde değerlendirmek? Onlarla başka bir şey yap? Sadece bir işlevi (işlevsel bir dilde yazılmış) nasıl derleyeceğinizi mi soruyorsunuz?
DW

Yanıtlar:


11

Mesele şu ki, fonksiyon kodlaması açısından çok fazla boşluk yok. Ana seçenekler şunlardır:

  • Terim yeniden yazma: işlevleri soyut sözdizimi ağaçları (veya bazı kodlamaları) olarak saklarsınız. Bir işlevi çağırdığınızda, sözdizim ağacını parametrelerini bağımsız değişkenle değiştirmek için el ile geçiş yaparsınız.Bu, zaman ve alan açısından kolay, ancak çok verimsizdir .

  • Kapanışlar: Bir işlevi, belki bir sözdizimi ağacını, daha olası makine kodunu temsil etmenin bir yolu var. Ve bu işlevlerde, argümanlarınıza bir şekilde referans olarak atıfta bulunursunuz. Bir işaretçi ofseti olabilir, bir tamsayı veya De Bruijn dizini olabilir, bir isim olabilir. Daha sonra bir işlevi kapanış olarak temsil edersiniz : işlevin tüm serbest değişkenlerini içeren bir veri yapısı ile eşleştirilmiş "talimatlar" (ağaç, kod vb.) İşlevi. Bir işlev gerçekten uygulandığında, ortamları, işaretçi aritmetiği vb. Kullanarak veri yapısındaki serbest değişkenlerin nasıl aranacağını bir şekilde bilir.

Eminim başka seçenekler vardır, ancak bunlar temel olanlar ve neredeyse her seçeneğin temel kapatma yapısının bir varyantı veya optimizasyonu olacağını sanıyorum.

Dolayısıyla, performans açısından, kapaklar neredeyse evrensel olarak terim yeniden yazımdan daha iyi performans gösterir. Varyasyonlardan hangisi daha iyi? Bu büyük ölçüde dilinize ve mimarinize bağlıdır, ancak "ücretsiz değişkenler içeren bir yapı ile makine kodu" şüpheli en verimli. Fonksiyonun ihtiyaç duyduğu her şeye (talimatlar ve değerler) ve daha fazlasına sahiptir ve çağrı büyük vadeli geçişler yapmaz.

Hem geçerli kodlama algoritması popüler fonksiyonel diller (Haskell, ML) kullanımı ile ilgileniyorum

Ben uzman değilim, ancak% 99'luk çoğu ML aroması, muhtemelen bazı optimizasyonlarla birlikte tarif ettiğim kapakların bazı varyasyonlarını kullanıyorum. Bkz bu perspektiften (muhtemelen tarih dışına) bir için.

Haskell tembel değerlendirme nedeniyle biraz daha karmaşık bir şey yapıyor: Spineless Tagless Graph Rewriting kullanıyor .

ve ayrıca elde edilebilecek en verimli olanda.

En verimli olan nedir? Tüm girdiler arasında en verimli olacak bir uygulama yoktur, bu nedenle ortalama olarak verimli uygulamalar alırsınız, ancak her biri farklı senaryolarda mükemmelleşir. Dolayısıyla, en çok ya da en az verimli olan kesin bir sıralama yoktur.

Burada sihir yok. Bir işlevi saklamak için, bir şekilde serbest değerlerini saklamanız gerekir , aksi takdirde işlevin kendisinden daha az bilgi kodlarsınız. Belki bazı serbest değerleri kısmi değerlendirme ile optimize edebilirsiniz, ancak bu performans için risklidir ve bunun her zaman durmasını sağlamak için dikkatli olmalısınız.

Ve belki de alan verimliliği elde etmek için bir tür sıkıştırma veya akıllı algoritma kullanabilirsiniz. Ancak, ya alan için ticaret zamanı yapıyorsunuz ya da bazı durumlar için optimize ettiğiniz ve diğerleri için yavaşladığınız durumdasınız.

Ortak durum için optimize ama ne ortak vaka olabilir olduğu gibi dilin, uygulama alanında, bir video oyunu için hızlı kod türüne değiştirebilirsiniz (sayı çatırdayan büyük girişli sıkı döngüler) daha muhtemelen farklıdır bir derleyici için hızlı olan nedir (ağaç geçişleri, iş listeleri vb.).

Bonus noktası: İşlev kodlu tamsayıları yerel tamsayılarla (C'de kısa, int vb.) Eşleyen böyle bir kodlama var mı? Hatta mümkün mü?

Hayır, bu mümkün değil. Sorun şu ki, lambda hesabı terimleri içgözlemlemenize izin vermiyor. Bir işlev bir Church-numeral ile aynı tipte bir argüman aldığında, o numaranın tam tanımını incelemeden onu çağırabilmelidir. Kilise kodlamaları ile ilgili olan şey budur: onlarla yapabileceğiniz tek şey onları aramaktır ve bununla yararlı olan her şeyi simüle edebilirsiniz, ancak maliyetsiz değil.

Daha da önemlisi, tamsayılar olası her ikili kodlamayı işgal eder. Eğer lambdalar tamsayı olarak gösterilseydi, kilise-uyuşmaz lambdaları temsil etmenin hiçbir yolu olmazdı! Veya, lambda'nın bir sayı olup olmadığını belirtmek için bir bayrak eklersiniz, ancak istediğiniz herhangi bir verimlilik muhtemelen pencereden dışarı çıkar.

DÜZENLEME: Bunu yazdığımdan beri, daha üst düzey işlevleri uygulamak için üçüncü bir seçeneğin farkındayım: işlev bozukluğu . Burada, her fonksiyon çağrısı, fonksiyon switcholarak hangi lambda soyutlamasının verildiğine bağlı olarak büyük bir ifadeye dönüşür . Buradaki ödünleşim, bunun tamamen bir program dönüşümüdür: parçaları ayrı ayrı derleyemez ve daha sonra bu şekilde birbirine bağlayamazsınız, çünkü önceden tüm lambda soyutlama setine sahip olmanız gerekir.

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.