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 switch
olarak 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.