Tamamen işlevsel programlamanın verimliliği


397

Herkes zorunluluk yerine tamamen işlevsel olarak programlama yaparken (yani yan etkilere izin verirken) olabilecek en kötü asimtotik yavaşlamanın ne olduğunu biliyor mu?

İtowlson tarafından yapılan açıklama : En iyi bilinen tahribatsız algoritmanın asimptotik olarak en iyi bilinen tahrip edici algoritmadan daha kötü olduğu herhangi bir sorun var mı?


6
Zorunlu programlama yapılırken olduğu gibi, ne olursa olsun.
R. Martinho Fernandes

3
@jldupont: Tabii ki hesaplamanın sonucunu döndürmek için. Birçok yan etkisi ücretsiz program mevcuttur. Girdilerini hesaplamaktan başka bir şey yapamazlar. Ama bu hala faydalı.
jalf

24
Fonksiyonel kodumu kötü yazarak istediğiniz kadar kötü yapabilirim! * sırıtış * Bence sorduğunuz şey "en iyi bilinen yıkıcı olmayan algoritmanın asimptotik olarak en iyi bilinen yıkıcı algoritmadan daha kötü olduğu herhangi bir sorun var mı?" ?
itowlson

2
İlgilendiğiniz yavaşlama türüne bir örnek verebilir misiniz. Sorunuz biraz belirsiz.
Peter Recore

5
Bir kullanıcı cevabını sildi, ancak 8-queens probleminin fonksiyonel versiyonunun n = 13 için bir dakikadan fazla sürdüğünü iddia etti. F # 'da 8 kraliçe: pastebin.com/ffa8d4c4 . Söylemeye gerek yok, tamamen işlev programım n = 20'yi bir saniyede hesaplıyor.
Juliet

Yanıtlar:


531

Göre Pippenger [1996] veri mutasyona olabilir biri saf olmayan Lisp için yazılmış bir algoritmaya (yavaş olmayan ve katı bir değerlendirme semantik vardır) tamamen işlevsel olan bir Lisp sistemi karşılaştırırken, O (çalışacak şekilde n ) tercüme edilebilir saf Lisp'de O ( n log n ) zamanında çalışan bir algoritmaya ( Ben-Amram ve Galil [1992] tarafından sadece işaretçiler kullanılarak rasgele erişim belleğini simüle etme konusundaki çalışmalarına dayanarak ). Pippenger, yapabileceğiniz en iyi algoritmalar olduğunu da belirler; saf olmayan sistemde saf sistemde are ( n log n ) olan O ( n ) problemleri vardır .

Bu yazı hakkında yapılması gereken birkaç uyarı var. En önemlisi Haskell gibi tembel fonksiyonel dilleri ele almamasıdır. Bird, Jones ve De Moor [1997] , Pippenger tarafından oluşturulan sorunun O ( n ) zamanda tembel bir işlevsel dilde çözülebildiğini , ancak bunların (veya bildiğim kadarıyla hiç kimsenin olmadığını veya Tembel bir işlevsel dil, mutasyonlu bir dil ile aynı asimtotik çalışma süresindeki tüm sorunları çözemez.

Pippenger'ın gerektirdiği sorun Ω ( n log n ) bu sonucu elde etmek için özel olarak inşa edilmiştir ve pratik, gerçek dünya problemlerini temsil etmek zorunda değildir. Sorun üzerinde biraz beklenmedik, ancak ispatın çalışması için gerekli olan birkaç kısıtlama vardır; özellikle sorun, gelecekteki girdilere erişemeden sonuçların çevrimiçi olarak hesaplanmasını ve girdinin sabit bir boyut kümesi yerine sınırsız olası atom kümesinden oluşmasını gerektirir. Ve kağıt, doğrusal çalışma süresinin saf olmayan bir algoritması için sadece (alt sınır) sonuçlar oluşturur; daha uzun çalışma süresi gerektiren sorunlar için, ekstra O (log n) doğrusal problemde görülen faktör, daha uzun çalışma sürelerine sahip algoritmalar için gerekli olan ilave işlemler sürecinde "emilebilir". Bu açıklamalar ve açık sorular Ben-Amram [1996] tarafından kısaca araştırılmıştır .

Uygulamada, birçok algoritma, değişebilir veri yapılarına sahip bir dilde olduğu gibi aynı işlevsellikte saf işlevsel bir dilde uygulanabilir. Tamamen işlevsel veri yapılarını verimli bir şekilde uygulamak için kullanılacak teknikler hakkında iyi bir referans için bkz. Chris Okasaki'nin "Tamamen Fonksiyonel Veri Yapıları" [Okasaki 1998] (tezinin genişletilmiş bir versiyonudur [Okasaki 1996] ).

Tamamen işlevsel veri yapıları üzerinde algoritmalar uygulamak isteyen herkes Okasaki'yi okumalıdır. Dengeli bir ikili ağaçla değişken belleği simüle ederek işlem başına her zaman en kötü O (log n ) yavaşlamasını sağlayabilirsiniz, ancak çoğu durumda bundan daha iyi yapabilirsiniz ve Okasaki, itfa edilmiş tekniklerden gerçeğe itfa edilen işi aşamalı olarak yapan zamanlardır. Tamamen işlevsel veri yapıları ile çalışmak ve analiz etmek biraz zor olabilir, ancak derleyici optimizasyonunda, paralel ve dağıtılmış hesaplamada ve sürüm oluşturma, geri alma ve geri alma gibi özelliklerin uygulanmasında yardımcı olan referans saydamlığı gibi birçok avantaj sağlar.

Tüm bunların sadece asimptotik çalışma sürelerini tartıştığını da unutmayın. Tamamen işlevsel veri yapılarını uygulamak için birçok teknik, çalışması için gerekli ekstra defter tutma ve söz konusu dilin uygulama detayları nedeniyle size belirli miktarda sabit faktör yavaşlaması sağlar. Tamamen işlevsel veri yapılarının faydaları bu sabit faktör yavaşlamalarından daha ağır basabilir, bu nedenle genellikle söz konusu soruna dayanarak ödünleşmeler yapmanız gerekecektir.

Referanslar


50
Pippinger, bu konuda tartışmasız otoritedir. Ancak sonuçlarının pratik değil teorik olduğunu vurgulamalıyız . İşlevsel veri yapılarını pratik ve verimli hale getirmek söz konusu olduğunda, Okasaki'den daha iyisini yapamazsınız.
Norman Ramsey

6
itowlson: Sorunuzu cevaplayacak kadar Pippenger okumadığımı itiraf etmeliyim; Okasaki tarafından atıf yapılan hakemli bir dergide yayınlandı ve iddialarının bu soru ile ilgili olduğunu ancak kanıtın anlaşılması için yeterli olmadığını belirlemeye yeteri kadar okudum. Gerçek dünya sonuçları için elde ettiğim acil paket, dengeli bir ikili ağaç kullanarak değiştirilebilir bir belleği simüle ederek bir O ( n ) saf olmayan algoritmayı O ( n log n ) saf bir algoritmaya dönüştürmenin önemsiz olmasıdır . Bundan daha iyisini yapamayan sorunlar var; Tamamen teorik olup olmadıklarını bilmiyorum.
Brian Campbell

3
Pippenger sonucu kapsamını sınırlayan iki önemli varsayım yapar: "çevrimiçi" veya "reaktif" hesaplamaları (sonlu girdileri tek bir çıktıya eşleyen hesaplamaların olağan modeli değil) ve girdilerin dizileri olduğu "sembolik" hesaplamaları dikkate alır sadece eşitlik için test edilebilen atomlar (yani, girdinin yorumu son derece ilkeldir).
Chris Conway

2
Çok iyi cevap; Tamamen işlevsel diller için karmaşıklığı hesaplamak için evrensel olarak kabul edilmiş bir model olmadığını eklemek isterim, saf olmayan dünyada birim maliyetli RAM makinesi nispeten standarttır (bu, şeyleri karşılaştırmayı daha zor hale getirir). Ayrıca saf / saf olmayan bir Lg (N) farkının üst sınırının, saf bir dilde dizilerin uygulanmasına bakarak sezgisel olarak kolayca açıklanabileceğini unutmayın (işlem başına lg (n) maliyeti (ve geçmiş olsun)) .
user51568

4
Önemli nokta: Tamamen işlevsel bir spesifikasyonu daha karmaşık bir verimli, tamamen işlevsel bir uygulamaya dönüştürmek, sonunda - otomatik veya elle - daha verimli safsızlık koduna çevirecekseniz çok az fayda sağlar. Bir kafeste tutabilirseniz, örneğin harici olarak yan etkisi olmayan bir işlevde kilitleyerek kirlilik o kadar da önemli değildir.
Robin Green

44

Aslında, tembellikle bile, asimptotik olarak etkili, tamamen işlevsel bir çözümün (saf lambda hesabında uygulanabilir bir çözüm) bilinmediği birkaç algoritma ve veri yapısı vardır.

  • Sözü edilen sendika bul
  • Karma tablolar
  • Diziler
  • Bazı grafik algoritmaları
  • ...

Bununla birlikte, "zorunlu" dillerde belleğe erişim O (1) iken teoride asimptotik olarak (yani sınırsız problem boyutları için) ve büyük bir veri kümesi içinde belleğe erişim her zaman O (log n) olarak kabul edilir. işlevsel bir dilde taklit edilebilir.

Ayrıca, aslında tüm modern fonksiyonel dillerin değiştirilebilir veriler sunduğunu ve Haskell'in bile saflıktan (ST monad) ödün vermeden sağladığını unutmamalıyız.


3
Veri kümesi fiziksel belleğe sığarsa, herhangi bir öğenin okunması için gereken süre üzerinde mutlak bir üst sınır bulmak mümkün olduğundan ona erişim O (1) 'dir. Veri kümesi girmezse, I / O hakkında konuşuyorsunuz ve bu şimdiye kadar baskın faktör olacaktır, ancak program yazılmıştır.
Donal Üyeleri

Tabii ki, harici belleğe erişim O (log n) işlemlerinden bahsediyorum. Ancak, her durumda bs konuşuyordum: harici bellek de O (1) -adreslenebilir olabilir ...
jkff

2
Fonksiyonel programlamaya kıyasla zorunlu programlamanın kazandığı en büyük şeylerden biri, bir durumun birçok farklı yönüne referans tutma ve tüm bu referansların yeni durumun karşılık gelen yönlerini gösterecek şekilde yeni bir durum üretme yeteneği olduğunu düşünüyorum. İşlevsel programlamanın kullanılması, mevcut genel durumun belirli bir sürümünün uygun yönünü bulmak için doğrudan silme işlemlerinin arama işlemleri ile değiştirilmesini gerektirir.
Supercat

İşaretçi modeli (O (log n) bellek erişimi, gevşek konuşma) bile, aşırı büyük ölçeklerde fiziksel olarak gerçekçi değildir. Işık hızı, farklı bilgi işlem ekipmanlarının birbirleriyle ne kadar hızlı iletişim kurabildiğini sınırlarken, şu anda inanılıyor belirli bir bölgede tutulabilir bilginin en fazla miktarda yüzey alanı ile sınırlı olduğunu.
dfeuer

36

Bu makale , birleşme-bulma algoritmasının bilinen tamamen işlevsel uygulamalarının, tamamen işlevsel bir arayüze sahip olan ancak dahili olarak değiştirilebilir verileri kullanan yayınladıklarından daha kötü asimptotik karmaşıklığa sahip olduğunu iddia etmektedir.

Diğer cevapların hiçbir zaman bir fark olmayabileceğini iddia etmesi ve örneğin, tamamen işlevsel kodun tek "dezavantajı", bunun paralelleştirilebilmesidir, size bu konularda fonksiyonel programlama topluluğunun bilinçliliği / tarafsızlığı hakkında bir fikir verir. .

DÜZENLE:

Aşağıdaki yorumlar, saf işlevsel programlamanın artıları ve eksileri hakkındaki önyargılı bir tartışmanın “işlevsel programlama topluluğundan” gelemeyebileceğine işaret etmektedir. İyi bir nokta. Belki de gördüğüm savunucular sadece bir yorum yapmak için “okuma yazma bilmiyor”.

Örneğin, bu blog gönderisinin fonksiyonel programlama topluluğunu temsil ettiği söylenebilecek biri tarafından yazıldığını düşünüyorum ve “tembel değerlendirme noktaları” nın bir listesi olduğundan, herhangi bir dezavantajdan bahsetmek için iyi bir yer olurdu. tembel ve tamamen işlevsel programlama olabilir. Aşağıdakilerin yerine iyi bir yer olurdu (teknik olarak doğru, ama komik olmama noktasına eğilimli):

Katı bir fonksiyonun katı bir dilde O (f (n)) karmaşıklığı varsa, tembel bir dilde de O (f (n)) karmaşıklığına sahiptir. Neden endişe? :)


4

Bellek kullanımında sabit bir üst sınır ile fark olmamalıdır.

İspat taslağı: Bellek kullanımında sabit bir üst sınır verildiğinde, o makinede gerçekte yürüttüğünüz gibi aynı asimptotik karmaşıklığa sahip bir zorunlu talimat kümesi yürüten bir sanal makine yazılabilmelidir. Bunun nedeni, değiştirilebilir belleği kalıcı bir veri yapısı olarak yönetebileceğiniz ve O (log (n)) okuma ve yazma olanağı sunabilmenizdir, ancak bellek kullanımında sabit bir üst sınır ile sabit bir belleğe sahip olabilirsiniz. O (1) 'e bozunur. Bu nedenle, fonksiyonel uygulama, VM'nin fonksiyonel uygulamasında çalışan zorunlu sürüm olabilir ve bu nedenle her ikisinin de aynı asimtotik karmaşıklığa sahip olması gerekir.


6
Bellek kullanımına ilişkin sabit bir üst sınır, insanların bu tür şeyleri nasıl analiz ettikleri değildir; keyfi olarak büyük fakat sınırlı bir bellek olduğunu varsayıyorsunuz. Bir algoritma uygularken, en basit girişten herhangi bir keyfi giriş boyutuna kadar nasıl ölçekleneceği ile ilgileniyorum. Bellek kullanımına sabit bir üst sınır koyarsanız, neden hesaplamanın ne kadar süre alacağına dair sabit bir üst sınır koymazsınız ve her şeyin O (1) olduğunu söyleyemezsiniz?
Brian Campbell

@Brian Campbell: Bu doğru. Ben sadece isterseniz, pratikte birçok durumda sabit faktördeki farkı göz ardı edebileceğinizi öneriyorum. M'den daha fazla bellek kullanmanın çalışma sürenizi en az bir günlük (m) faktörü kadar azalttığından emin olmak için bellek ve zaman arasında uzlaşırken farkın hala farkında olunması gerekir.
Brian

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.