Y birleştirici ve kuyruk çağrı optimizasyonları


20

F # içindeki Y birleştiricisinin tanımı

let rec y f x = f (y f) x

f, ilk argüman olarak, özyinelemeli alt problemler için bir miktar devam etmeyi beklemektedir. Yf'yi bir devamı olarak kullanarak, geliştirebileceğimiz gibi f'nin birbirini izleyen çağrılara uygulanacağını görüyoruz.

let y f x = f (y f) x = f (f (y f)) x = f (f (f (y f))) x etc...

Sorun şu ki, a priori, bu şema herhangi bir kuyruk çağrısı optimizasyonu kullanmayı engeller: gerçekten de f'lerde bekleyen bir işlem olabilir, bu durumda f ile ilişkili yerel yığın çerçevesini değiştiremeyiz.

Yani :

  • bir tarafta, Y birleştiricisini kullanmak işlevin kendisinden açıkça farklı bir devam gerektirir .
  • TCO'yu uygulamak için, f'de bekleyen herhangi bir işlemimiz yok ve sadece f'nin kendisini çağırıyoruz.

Bu ikisinin uzlaştırılabileceği herhangi bir yol biliyor musunuz? Akümülatör numarasına sahip bir Y veya CPS numarasına sahip bir Y gibi mi? Yoksa yapılabilecek bir yol olmadığını kanıtlayan bir argüman mı?


Rec anahtar çalışmasını y uygulamanıza eklediniz mi? Okumamdan buna ihtiyacı olduğunu düşünmeliyim ..
Jimmy Hoffa

Kuyruk çağrısını optimize etmediğine dair kanıtınız var mı? Bu işlev için IL'yi okumak isteyebileceğinizi düşünmeliyim ve bakın, derleyici bir şey bulmak için yeterince akıllıysa şaşırmazdım ..
Jimmy Hoffa

düz, çözülmemiş bir özyineleme durumunda, bunu yapmaz: ancak yığın çerçevesinin y çağrısı yoluyla yeniden kullanılmasına bağlı olarak böyle bir şeye izin vermek için yeniden yazabilirsiniz . evet IL'yi görmeniz gerekebilir, bu konuda deneyim yok.
nicolas

5
Bir hesap açtım ve buraya yorum yapmak için 50 puan aldım. Bu soru gerçekten ilginç. Bence tamamen bağlı f. Bunun bir thunk ile ykuyruk çağırabileceğini görebiliriz, ancak dediğin gibi bekleyen bir operasyon olabilir. Daha kuyruk dostu olan ayrı bir birleştirici olup olmadığını bilmek ilginç olurdu. Acaba bu sorunun CS Stackexchange sitesinde daha iyi dikkat çekecek mi? f(y f)f
John Cartwright

Yanıtlar:


4

Bu ikisinin uzlaştırılabileceği herhangi bir yol biliyor musunuz?

Hayır, ve iyi bir sebeple, IMHO.

Y-birleştirici teorik bir yapıdır ve sadece lambda kalkülüs turingini tamamlamak için gereklidir (unutmayın, lambda kalkülüsünde döngüler yoktur veya lambdaların özyineleme için kullanabileceğimiz isimleri yoktur).

Bu nedenle, Y birleştiricisi gerçekten büyüleyici.

Ama : Kimse gerçekte kullandığı fiili özyineleme için Y-bağdaştırıcının! (Belki eğlence dışında, gerçekten işe yaradığını göstermek için.)

Kuyruk çağrısı optimizasyonu, OTOH, adından da anlaşılacağı gibi, bir optimizasyondur. Bir dilin üstünlüğüne hiçbir şey katmaz, bunun nedeni yalnızca yığın alanı ve önem verdiğimiz özyinelemeli kodların performansı gibi pratik etkenlerdir.

Yani sorunuz şöyle: Beta azaltma için donanım desteği var mı? (Beta azaltma, lambda ifadelerinin nasıl azaltıldığını biliyorsunuz.) Ama hiçbir işlevsel dil (bildiğim kadarıyla) kaynak kodunu çalışma zamanında beta azalacak lambda ifadelerinin bir temsiliyle derlemez.


2
Y-birleştirici, her kullanımdan sonra çözülmeye devam eden bir düğümü yeniden denemek gibidir. Çoğu sistem bunu kısa sürede keser ve düğümü meta seviyeye bağlar, böylece asla tekrarlanması gerekmez.
Dan

1
Son paragrafa gelince, tembel değerlendirme yapmak için kalbinde grafik azaltmayı kullanan Haskell'i düşünün . Ama benim favorim, Church-Rosser kafesindeki yolu her zaman tam normal forma en az indirgeyle götüren optimal azaltma . Asperti ve Guerrini'nin Fonksiyonel Programlama Dillerinin Optimal Uygulaması'nda ortaya çıktığı gibi . Ayrıca bkz. BOHM 1.1 .
Dan

@DanD. Bağlantılar için teşekkürler, daha sonra postscript farkında bir tarayıcıda deneyeceğim. Elbette benim için öğrenilecek bir şeyler var. Ancak, derlenmiş haskell'in grafikte azalma sağladığından emin misiniz ? Bundan şüphe ediyorum.
Ingo

1
Aslında grafik azaltma kullanmaktadır: "GHC, spinless etiketsiz G-makinesine (STG) derlenir. Bu, kavramsal bir grafik azaltma makinesidir (yani, yukarıda açıklandığı gibi grafik azaltmalarını gerçekleştiren sanal bir makine)." Gönderen ... STG makinede daha fazla bilgi için bkz Simon Peyton Jones'un Spineless Etiketsiz G-makinesi: stok donanım üzerinde uygulama tembel fonksiyonel dilleri .
Dan

@DanD. bağladığınız aynı makalede, GHC'nin "son olarak gerçek makine koduna (muhtemelen GCC'yi kullanarak C aracılığıyla) derlemeden önce bu gösterimde bir dizi optimizasyon yaptığını" da okur.
Ingo

0

Bu cevaptan tam olarak emin değilim, ama gelebileceğim en iyisi bu.

Y birleştirici doğası gereği tembeldir, katı dillerde tembellik ekstra lambdalar aracılığıyla manuel olarak eklenmelidir.

let rec y f x = f (y f) x

Tanımınız sona erdirmek için tembellik gerektiriyor gibi görünüyor veya (y f)argüman asla değerlendirmeyi bitirmeyecek ve fkullanılıp kullanılmayacağını değerlendirmek zorunda kalacak . Tembel bir bağlamda TOK daha karmaşıktır ve ayrıca sonucu ile (y f)uygulama kompozisyonu tekrarlanmaz x. Bu ihtiyacın n özyineleme derinliği olduğu O (n) bellek almak emin değilim, ama şüphe gibi bir şey ile mümkün olduğu gibi aynı TOC elde edebilirsiniz (Haskell için geçiş çünkü aslında bilmiyorum F #)

length acc []    = acc
length acc (a:b) = length (acc+1) b 

Zaten farkında değilseniz, arasındaki fark foldlfoldl' Haskell ve Haskell duruma biraz ışık tutabilir. foldlistekli bir dilde yapılacak gibi yazılmıştır. Ancak TOC'lu olmak yerine, aslında daha kötüdür foldrçünkü aktüatör, kısmen değerlendirilemeyen potansiyel olarak büyük bir thunk saklar. (Bu hem kıvrım hem de kıvrımın neden sonsuz listelerde çalışmadığına foldl'ilişkindir .) Böylece Haskell'in daha yeni versiyonlarına , fonksiyonun muazzam bir thunk oluşturulmasını sağlamak için her tekrarladığında akümülatörün değerlendirmesini zorlayan eklenmiştir. Http://www.haskell.org/haskellwiki/Foldr_Foldl_Foldl%27'nin bunu benden daha iyi açıklayabileceğinden eminim .

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.