Fonksiyonel programlamada durum problemleri ile başa çıkmak


19

Öncelikle bir OOP bakış açısıyla nasıl programlanacağını öğrendim (çoğumuz gibi, eminim), ancak sorunları fonksiyonel şekilde nasıl çözeceğini öğrenmek için çok zaman harcadım. FP ile hesaplama problemlerinin nasıl çözüleceğine dair iyi bir kavrayışım var, ancak daha karmaşık problemler söz konusu olduğunda kendimi her zaman değişebilir nesnelere ihtiyaç duyduğumu görüyorum. Örneğin, bir parçacık simülatörü yazıyorsam, değiştirilebilir bir konuma sahip parçacık "nesneleri" nin güncellenmesini isteyeceğim. Doğal olarak "durumsal" problemler tipik olarak fonksiyonel programlama teknikleri kullanılarak nasıl çözülür?


4
İlk adım muhtemelen sorunların doğası gereği durumsal olmadığını fark etmektir.
Telastyn

4
Bir veritabanına yazmak veya bir GUI çizmek gibi bazı sorunlar doğası gereği durumsaldır. Parçacık simülatörü örneğimi ele alırsak, bunun hakkında düşünmenin alternatif bir yolu ne olurdu? Durumdan kaçınmak için konumlarını her güncellediğinde yeni parçacıklar döndürmek, gerçek dünyanın iyi bir modeli değil, bana verimsiz görünüyor.
Andrew Martin

4
Belki de veritabanı örneği dışında, bu sorunlar doğası gereği durumsal değildir . Örneğin, GUI programlama için, gerçekten değişebilir durumu zayıf, örtük bir zaman modeli olarak kullanıyorsunuz ; fonksiyonel reaktif programlama , birleştirebileceğiniz olay akışları sağlayarak duruma güvenmeden zamanı açıkça modellemenizi sağlar .
Tikhon Jelvis

1
Daha basit bir çözüm var: FP teknikleriyle kolayca modellenemeyen bir soruna geldiğinizde, çözmek için fonksiyonel programlama kullanmayın. İş ve her şey için doğru araç ...
Mason Wheeler

1
@AndrewMartin Gerçek dünyanın iyi bir modeli değil mi? Fizikte gerçek dünyayı modellemek için kullanılan matematik tamamen işlevseldir. İyi bir çöp toplayıcı ile bir nesneyi tahsis etmek, bir işaretçiyi çarpmak kadar ucuzdur ve toplama süresi, canlı nesne sayısıyla orantılıdır . Herhangi bir şey varsa, fonksiyonel programlamadaki en büyük verimsizlik kaynağının önbellek açısından verimli olmayan veri yapılarını kullanmak olduğuna bahse girerim. Bağlantılı listeler ve ikili ağaçlar tam olarak önbellek verimliliğinin posterleri değildir.
Doval

Yanıtlar:


21

İşlevsel programlar durumu çok iyi idare eder, ancak ona farklı bir bakış açısı gerektirir. Konum örneğiniz için göz önünde bulundurulması gereken bir nokta , konumunuzun sabit bir değer yerine zamanın bir işlevi olması . Bu, sabit bir matematiksel yolu izleyen parçacıklar için iyi çalışır, ancak yoldaki bir değişikliği ele almak için, örneğin bir çarpışma sonrası gibi farklı bir stratejiye ihtiyacınız vardır.

Buradaki temel strateji, bir durumu alan ve yeni durumu döndüren işlevler oluşturmaktır . Bu yüzden bir parçacık simülatörü Set, parçacıkların giriş olarak alınması ve Setbir zaman adımından sonra yeni parçacıkların geri dönmesini sağlayan bir işlev olacaktır . Daha sonra tekrar tekrar girişini önceki sonucuna ayarlanmış olarak bu işlevi çağırırsınız.


5
+1 FP'de devlete sahip olmak sorun değil, sadece değişebilir durumda değil .
jhewlett

1
Bu anlayış için teşekkürler. Verimsizlik konusundaki endişelerim @logc tarafından engellendi; devletin nasıl dönüştürüldüğüne ilişkin teknik detaylar, dilin kendisinin çözmesi gereken düşük seviyeli bir uygulama problemidir. Rich Hickey'in bunu bir videoda Clojure ile nasıl yaptığını izlediğini izledim.
Andrew Martin

1
@jhewlett: Daha kesin olmak gerekirse: FP'nin durumu, hatta değişebilir durumu vardır, ancak bunları değişken değişkenler kullanarak temsil etmezler.
Giorgio

9

@KarlBielefeldt tarafından belirtildiği gibi, böyle bir soruna işlevsel yaklaşım, sorunu önceki bir durumdan yeni bir durum döndürmek olarak görmektir. Fonksiyonların kendileri herhangi bir bilgi tutmazlar, bu nedenle m durumunu her zaman n durumunu n olarak güncellerler .

Sanırım bu verimsiz olduğunu düşünüyorsunuz çünkü yeni durumu hesaplarken önceki durumun hafızada tutulması gerektiğini varsayıyorsunuz . Tamamen yeni bir durum yazmak veya eskisini yeniden yazmak arasındaki seçimin işlevsel bir dil açısından bir uygulama detayı olduğuna dikkat edin.

Örneğin, bir milyon tamsayı listem var ve onda birini bir birim artırmak istiyorum. Tüm listeyi onuncu konumunda yeni bir numarayla kopyalamak boşa harcanır, haklısınız; ancak bu işlemi dil derleyicisine veya yorumlayıcıya açıklamanın yalnızca kavramsal yoludur. Derleyici veya yorumlayıcı ilk listeyi almakta ve onuncu pozisyonun üzerine yazmakta serbesttir.

İşlemi bu şekilde tanımlamanın avantajı, derleyicinin birçok iş parçacığının aynı listeyi farklı konumlarda güncellemek istediği durum hakkında mantık yürütebilmesidir. İşlem "bu konuma git ve bulduklarının üzerine yaz" olarak tanımlanırsa, üzerine yazmaların çarpışmamasını sağlamaktan sorumlu olan derleyici değil, programcıdır.

Bütün bunlarla birlikte, Haskell'de bile, "devleti tutmak" bir sorun için daha sezgisel bir çözüm olan durumları modellemeye yardımcı olan bir Devlet monad var. Ama aynı zamanda "bulmak bazı sorunları fark lütfen bir veritabanına yazmak gibi, doğal olarak durum bilgisi " var Datomic gibi değişmez çözümler . Bunun bir kavram olduğunu anlayana kadar şaşırtıcı olabilir, ancak bunun gerçekleştirilmesi gerekmez.


4
Ben büyük bir listeyi güncelleme hakkında pasaj yanıltıcı olduğunu düşünüyorum; Bu optimizasyonu sizin için gerçekleştirecek herhangi bir derleyici bilmiyorum. Derleyici bunu yapabilse bile, yalnızca listenin önceki sürümlerine bağlı kalmamanız durumunda mümkündür. Gerçek çözüm, tek eleman değiştirmek için her şeyi kopyalama gerektirmeyen bir liste veri yapısını kullanmaktır.
Doval

@Doval: "Derleyici bunu yapabilse bile, yalnızca listenin önceki sürümlerine bağlı kalmamanız durumunda mümkündür.": Bu bana Clean'teki benzersiz türleri hatırlatıyor.
Giorgio

4

Doğru zihinsel modele abone olmak, kişinin devlet hakkında daha iyi düşünmesine ve yönetmesine yardımcı olur. Zihnimde, en iyi zihinsel model flip-book . Bu tıklandığında, FP'nin dünya durumunu yakalayan kalıcı veri yapılarına yoğun bir şekilde eğildiğini ve bu durumun herhangi bir mutasyon olmadan bu duruma geçiş yapmak için kullanıldığını anlayacaksınız.

Rich Hickey bu fikirleri aydınlatır:

Başka görüşmeler de var , ancak bu sizi doğru yönde göndermelidir.


3

Büyük ve orta derecede büyük uygulamalar yazarken, uygulamanın durum bilgisi olan ve durum bilgisi olmayan bölümleri arasında ayrım yapmanın genellikle yararlı olduğunu gördüm.

Durum bilgisi olan bölümdeki sınıflar / veri yapıları, uygulamanın verilerini saklar ve bu bölümdeki işlevler, uygulama verilerinin üstü kapalı bilgisi ile çalışır.

Durum bilgisi olmayan bölümdeki sınıflar / veri yapıları / işlevleri uygulamanın tamamen algoritmik yönlerini desteklemek için vardır. Uygulamanın verileri hakkında örtük bilgi sahibi değillerdir. Tamamen işlevsel bir yapıda çalışırlar. Uygulamanın durum bilgisi olan kısımları, uygulamanın durumsuz bölümünde çalışan işlevlerin bir yan etkisi olarak durum değişikliği yaşayabilir.

En zor kısım vatansız bölüme hangi sınıfların / işlevlerin ve durum bilgisi olan bölüme hangi sınıfların / işlevlerin yerleştirileceğini bulmak ve bunları ayrı dosyalara / kitaplıklara yerleştirmek için disipline sahip olmaktır.


Bu soruya nasıl cevap veriyor? (değil aşağı oy)
kravemir

@kravemir, ister OOP ister FP kullanarak bir uygulama yazarsanız, uygulamanın durumunun nerede olduğunu anlamalısınız.
R Sahu
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.