İşlevsel programlama nesne yöneliminin üst kümesi midir?


26

Ne kadar işlevsel programlama yaparsam, o kadar çok hissederim ki, bir soğanın tabakası, önceki tabakaları kapsayan bir soyutlama tabakası ekler.

Bunun doğru olup olmadığını bilmiyorum, bu yüzden yıllarca birlikte çalıştığım OOP prensiplerinin dışına çıkmak, herhangi birinin ne kadar işlevsel olduğunu veya hiçbirini doğru şekilde göstermediğini açıklayabilir: Kapsülleme, Soyutlama, Kalıtım, Polimorfizm

Sanırım hepimiz söyleyebileceğimizi söyleyebilirim, evet, tüllerle kapsülleme var mı, yoksa tüller teknik olarak "işlevsel programlama" nın bir gerçeği olarak mı sayılıyor, yoksa bunlar sadece bir dilin faydası mı?

Haskell'in "arayüzler" gereksinimini karşılayabileceğini biliyorum, ancak bu yöntemin işlevsel bir gerçek olup olmadığından emin değil misiniz? Sanırım functorların matematiksel bir temeli olduğu gerçeği, belki de fonksiyonel beklenti içinde kesin bir yapı olduğunu söyleyebilirsiniz.

Lütfen, işlevselliği düşündüğünüzün OOP'un 4 ilkesini nasıl yerine getirdiğini veya yerine getirmediğini ayrıntılarıyla belirtin.

Düzenleme: Fonksiyonel paradigma ve nesne yönelimli paradigma arasındaki farkları çok iyi anlıyorum ve bugünlerde her ikisini de yapabilen çok sayıda çoklu paradigma dili olduğunu fark ettim. Gerçekten sadece fp'nin (zekice düşünün, haskell gibi) listelenen 4 şeyden herhangi birini nasıl yapabileceğini ya da neden hiçbirini yapamayacağının tanımlarını arıyorum. yani “Kapsülleme kapaklarla yapılabilir” (veya bu inancında yanılmıyorsam, lütfen nedenini belirtiniz).


7
Bu 4 ilke OOP'yi “yapmaz”. OOP, sınıfları, sınıf aramasını ve örneklerini kullanarak bunları “çözer”. Ancak, işlevsel programlamada bunları başarmanın yolları varsa, ben de bir cevap istiyorum.
Öforik

2
@Euphoric Tanıma bağlı olarak, OOP yapar .
Konrad Rudolph

2
@KonradRudolph Bir çok insanın bu şeyleri ve OOP'un benzersiz özellikleri olarak getirdiği faydaları iddia ettiğini biliyorum. "Polimorfizm" in "alt tip polimorfizm" anlamına geldiği varsayılırsa, ikinci ikisinin de OOP ile bütünleşik olduğunu söyleyebilirim. Fakat henüz kesin olarak OOP dışı yaklaşımları hariç tutan kapsülleme ve soyutlamanın yararlı bir tanımına rastlamadım. Ayrıntıları gizleyebilir ve bunlara erişimi kısıtlayabilirsiniz, Haskell'de bile. Haskell'in ayrıca geçici polimorfizmi vardır, sadece alt tip polimorfizmini değil - soru, "alt tip" biti önemli midir?

1
@KonradRudolph Bu daha fazla kabul edilebilir yapmaz. Eğer bir şey varsa, tekrar düşünmek için nedenini yaymak ve yaymak olanlara vermek teşvik edicidir.

1
Soyutlama, herhangi bir programlamanın, en azından ham makine kodunun ötesindeki herhangi bir programlamanın özüdür. Enkapsülasyon, OOP'dan çok uzun zaman önce olmuştur ve fonksiyonel programlamanın özüdür. Kalıtım veya polimorfizm için açık sözdizimi içermesi için işlevsel bir dil gerekmez. Sanırım bu 'hayır' anlamına geliyor.
sdenham

Yanıtlar:


44

İşlevsel programlama, OOP'nin üzerinde bir katman değildir; bu tamamen farklı bir paradigma. OOP'yi işlevsel bir tarzda yapmak mümkündür (F # bu amaç için yazılmıştır) ve spektrumun diğer ucunda Haskell gibi nesnelere yönelme ilkelerini açıkça reddeden şeyler vardır.

Modülleri ve işlevleri destekleyecek kadar gelişmiş herhangi bir dilde kapsülleme ve soyutlama yapabilirsiniz. OO, kapsülleme için özel mekanizmalar sağlar, ancak OO'ya özgü bir şey değildir. OO noktası bahsettiğiniz ikinci çift: miras ve polimorfizm. Konsept resmen Liskov ikame olarak bilinir ve nesne yönelimli programlama için dil düzeyinde destek olmadan elde edemezsiniz. (Evet, bazı durumlarda taklit etmek mümkündür, ancak OO'nun masaya getirdiği avantajların çoğunu kaybedersiniz.)

İşlevsel programlama, Liskov'un ikamesine odaklanmıyor. Soyutlama seviyesini artırmaya ve gerçekten bir şeyi yapan bir şeyi yapan (sadece bir şeyi hesaplamanın tersine) rutinleri kullanmak için kullanılan işlevsel bir programcı olan "yan etkileri" olan değişken durum ve rutinlerin kullanımını en aza indirmeye odaklanıyor korkutucu. Fakat yine de, programcının diline ve becerisine bağlı olarak birlikte kullanılabilecek veya kullanılamayacak tamamen ayrı paradigmalardır.


1
Peki, kalıtım (gerektiğinde istisnai olan bu nadir durumlarda) kompozisyon üzerinden elde edilebilir ve tip düzeyinde kalıtımdan daha temizdir. Polimorfizm, özellikle polimorfik türlerin varlığında doğaldır. Fakat elbette, FP'nin OOP ve prensipleriyle ilgisi olmadığını kabul ediyorum.
SK-mantık

Sahte yapmak her zaman mümkündür - nesneleri seçtiğiniz herhangi bir dilde uygulayabilirsiniz. Yine de başka her şeye katılıyorum :)
Eliot Ball

5
İşlevsel programcılar tarafından "yan etkiler" teriminin kullanıldığını (veya öncelikle kullanıldığını) sanmıyorum.
sepp2k

4
@ sepp2k: Terimi icat ettiklerini söylemedi, sadece çimlerinden inmeyi reddeden çocuklara atıfta bulunmak için normalde kullandığı gibi aynı tonu kullanarak onu kullandıklarını söylemedi.
Aaron,

16
@Aaronaught beni rahatsız eden çimlerimdeki çocuklar değil, onların kanlı yan etkileri! Çimimin her yerine mutasyon yapmayı bırakırlarsa, onlara aldırış etmem.
Jimmy Hoffa

10

Aşağıdaki sezgiyi OOP ile FP'yi karşılaştırmak için yararlı buluyorum.

FP'yi bir OOP süperseti olarak düşünmek yerine, OOP ve FP'yi, sahip olduğunuz benzer bir temel hesaplama modeline bakmanın iki alternatif yolu olarak düşünün:

  1. Gerçekleştirilen bazı işlemler,
  2. Operasyona bazı girdi argümanları,
  3. İşlemin tanımını etkileyebilecek bazı sabit veri / parametreler,
  4. bazı sonuç değerleri ve
  5. muhtemelen bir yan etki.

OOP’de bu

  1. Yürütülen bir yöntem
  2. Bir yöntemin girdi argümanları,
  3. yöntemin çağrıldığı, üye değişkenler biçimindeki bazı yerel verileri içeren nesne,
  4. yöntemin dönüş değeri (muhtemelen geçersiz),
  5. yöntemin yan etkileri.

FP’de bu yakalanır

  1. Yürütülen bir kapama,
  2. kapanmanın girdi argümanları,
  3. kapatmanın yakalanan değişkenleri,
  4. kapatmanın geri dönüş değeri,
  5. kapatmanın olası yan etkileri (Haskell gibi saf dillerde bu çok kontrollü bir şekilde gerçekleşir).

Bu yorumla, bir nesne aynı yerel olmayan değişkenleri (nesnenin koleksiyondaki tüm kapaklarda ortak olan üye değişkenleri) yakalayan bir kapaklar topluluğu (yöntemleri) olarak görülebilir. Bu görüş aynı zamanda nesne yönelimli dillerdeki kapakların çoğu zaman tam olarak tek bir yöntemle nesne olarak modellenmesiyle de desteklenir.

Bence farklı bakış açıları, nesneye yönelik bakış açısının nesnelere (veri) odaklanırken ortaya çıktığını düşünüyorum.


8

OOP için kimin tanımını istediğine bağlı. Beş kişiye sorun, muhtemelen altı tanım elde edersiniz. Wikipedia diyor ki :

Nesnelerin arkasındaki fikir birliği tanımını veya teorisini bulma girişimleri pek başarılı olmadı

Bu yüzden ne zaman birileri kesin bir cevap verirse, onu bir tuz tuzu ile alın.

Dedi ki, evet, FP, o yapılacak iyi bir argüman var olan bir paradigma olarak OOP bir üst. Özellikle Alan Kay'ın nesne yönelimli programlama terimindeki tanımı bu görüşe aykırı değildir (ancak Kristen Nygaard'ın ). Kay'nın gerçekten ilgilendiği şey, her şeyin bir nesne olduğu ve bu mantığın, nesnenin arasına mesajlar iletilerek uygulanmasıydı.

Sorunuz için belki de daha ilginç olanı, sınıflar ve nesneler, fonksiyonların döndürdüğü fonksiyonlar ve kapanışlar olarak düşünülebilir (bir kerede sınıflar ve yapıcılar gibi davranır). Bu prototip tabanlı programlamaya çok yakın geliyor ve aslında JavaScript tam da bunu yapmayı sağlıyor.

var cls = function (x) {
    this.y = x;
    this.fun = function () { alert(this.y); };
    return this;
};

var inst = new cls(42);
inst.fun();

(Elbette JavaScript, tamamen işlevsel programlamada yasadışı olan, ancak kesin bir OOP tanımında gerekli olmayan mutasyona izin verir.)

Yine de daha önemli soru şudur: Bu , OOP'nin anlamlı bir sınıflandırması mıdır? Fonksiyonel programlamanın bir alt kümesi olarak düşünmek faydalı mı? Bence çoğu durumda öyle değil.


1
Paradigmaları değiştirdiğimde çizginin nereye çizilmesi gerektiğini düşünmenin anlamlı olabileceğini düşünüyorum. Eğer fp'de subtypal polimorfizm elde etmenin bir yolu olmadığı söylenirse, fp'yi onunla iyi uyuşacak bir şeyi modellemek için kullanmaya zahmet etmeyeceğim. Bununla birlikte, mümkün olsa da, fp uzayda yoğun bir şekilde çalışırken, ancak birkaç niş alanda subtypal polimorfizm istemek için, iyi bir şekilde yapmak için iyi bir yol elde etmek için zaman alabilir (iyi bir yol mümkün olmayabilir). Açıkçası, eğer sistemin çoğunluğu buna uyuyorsa, OOP kullanmak daha iyi olacaktır.
Jimmy Hoffa

6

OO gibi FP, iyi tanımlanmış bir terim değildir. Farklı, bazen birbiriyle çelişen tanımları olan okullar var. Ortak olanlarını alırsanız, aşağıya inersiniz:

  • fonksiyonel programlama birinci sınıf fonksiyonlarla programlamadır

  • OO programlama, en azından kısıtlanmış bir dinamik olarak çözülmüş aşırı yükleme şekliyle birleştirilmiş polimorfizmle programlamadır . (Bir not: OO çevrelerinde polimorfizm genellikle dahil etme polimorfizmi anlamına gelirken, FP okulları genellikle parametrik polimorfizm anlamına gelir .)

Başka her şey ya başka yerlerde var ya da bazı durumlarda mevcut değil.

FP ve OO iki soyutlama aracıdır. Her birinin kendi güçlü ve zayıf yönleri vardır (örneğin, ifade probleminde farklı bir tercih edilen uzatma yönüne sahiptirler), ancak hiçbiri aslında diğerinden daha güçlü değildir. Bir FP çekirdeği üzerinde bir OO sistemi kurabilirsiniz (CLOS böyle bir sistemdir). Birinci sınıf fonksiyonları elde etmek için bir OO çerçevesi kullanabilirsiniz (örneğin lambda fonksiyonlarının C ++ 11'de tanımlanma şeklini görün).


Bence 'birinci dereceden fonksiyonlar' yerine 'birinci sınıf fonksiyonlar' demek istiyorsun.
dan_waterworth

Errr ... C ++ 11 lambdalar pek birinci sınıf bir fonksiyon değildir: Her lambda kendi özel tip tipine sahiptir (tüm pratik amaçlar için, anonim bir yapı), yerel bir fonksiyon gösterici tipiyle uyumlu değildir. Ve std::functionhem fonksiyon göstericileri hem de lambdaların atanabildiği, nesne yönelimli değil, kesinlikle geneldir. Bu şaşırtıcı değil, çünkü nesne yönelimli sınırlı polimorfizm markası (alt tip polimorfizmi) parametrik polimorfizmden (hatta Hindley-Milner bile, tam Sistem F-omega'yı bile) kesinlikle daha az güçlü.
pyon

Saf fonksiyonel dillerle ilgili bir ton tecrübem yok, ancak kapanışlar içinde bir statik yöntem sınıfları tanımlayabilir ve onları farklı bağlamlara aktarabilirseniz, (belki de garip bir şekilde) en azından yarı yolda olduğunuzu söyleyebilirim. fonksiyonel stil seçenekleri orada. Çoğu dilde katı paramlar etrafında çalışmanın birçok yolu vardır.
Erik,

2

Yok hayır; OOP, prosedürel programlamanın bir üst kümesi olarak görülebilir ve temelde işlevsel paradigmadan farklıdır, çünkü örnek alanlarda temsil edilen bir duruma sahiptir. İşlevsel paradigmada değişkenler, istenen sonucu elde etmek için sabit verilere uygulanan işlevlerdir.

Aslında fonksiyonel programlamayı bir OOP alt kümesi düşünebilirsiniz; Tüm derslerinizi değiştirilemez hale getirirseniz, bir tür işlevsel programlamaya sahip olduğunuzu düşünebilirsiniz.


3
Immutable sınıflar daha üst düzey fonksiyonlar yapmaz, anlama veya listeyi kapatmaz. Fp bir altküme değildir.
Jimmy Hoffa,

1
@Jimmy Hoffa: Benzer türden veya daha fazla nesne alan tek bir metodu olan ve aynı zamanda bu benzer tipteki bir nesneyi döndüren bir sınıf yaratarak daha yüksek oreder işlevini kolayca taklit edebilirsiniz (yöntem olan ve alan içermeyen tür) . Liste zorunluluğu paradigma değil programlama diliyle ilgili bir şey değildir (Smalltalk onu destekler ve OOP'dir). Kapaklar C # 'da mevcuttur ve Java' da da eklenecektir.
m3th0dman

Evet, C # 'nın kapanışları vardır, fakat bunun nedeni çok paradigma olduğu için, diğer fp parçalarıyla birlikte (ebediyen minnettar olduğum için) başka fp parçalarıyla birlikte kapanmalar eklenmiştir, ancak onların bir oop dilinde var olmaları onları oop yapmaz. Daha yüksek dereceli fonksiyon hakkında iyi bir nokta olsa da, bir sınıfta bir yöntemin kapsüllenmesi aynı davranışı sağlar.
Jimmy Hoffa

2
Evet, ancak kullanım durumları değiştirmek için kapak kullanırsanız, yine de işlevsel bir paradigma programlayabilir misiniz? Mesele şu ki - işlevsel paradigma, üst düzey işlevler, özyineleme veya kapanmalar ile ilgili olmayan devlet eksikliği ile ilgilidir.
m3th0dman

fp tanımı üzerine ilginç düşünce .. Bu konuda daha fazla düşünmem gerekecek, gözlemlerinizi paylaştığınız için teşekkürler.
Jimmy Hoffa

2

Cevap:

Vikipedi, İşlevsel Programlama hakkında , istediğiniz örneklerden bazıları ile ilgili harika bir makaleye sahiptir . @Konrad Rudolph OOP makalesine bağlantıyı zaten verdi .

Bir paradigmanın diğerinin bir süper seti olduğunu sanmıyorum. Programlamaya yönelik farklı bakış açılarıdır ve bazı problemler bir bakış açısıyla, bazıları ise diğerinden daha iyi çözülür.

Sorunuz FP ve OOP'un tüm uygulamaları ile daha da karmaşıklaşıyor . Her dilin, sorunuza herhangi bir iyi cevapla alakalı kendi tuhaflıkları vardır.

Giderek Teğet Rambling:

Scala gibi bir dilin size her iki dünyanın da en iyisini sunmaya çalıştığı fikrini seviyorum. İki dünyanın da komplikasyonlarını sağlamasından endişe ediyorum.

Java bir OO dilidir, ancak sürüm 7 bir çeşit kapatmayı taklit etmek için kullanılabilecek bir "kaynakları ile dene" özelliği ekledi. Burada, başka bir işlevin ortasındaki "a" yerel değişkenini, bu işleve görünür hale getirmeden güncellemeyi taklit eder. Bu durumda, diğer işlevin ilk yarısı ClosureTry () yapıcısı ve ikinci yarısı close () yöntemidir.

public class ClosureTry implements AutoCloseable {

    public static void main(String[] args) {
        int a = 1;
        try(ClosureTry ct = new ClosureTry()) {
            System.out.println("Middle Stuff...");
            a = 2;
        }
        System.out.println("a: " + a);
    }

    public ClosureTry() {
        System.out.println("Start Stuff Goes Here...");
    }

    /** Interface throws exception, but we don't have to. */
    public void close() {
        System.out.println("End Stuff Goes Here...");
    }
}

Çıktı:

Start Stuff Goes Here...
Middle Stuff...
End Stuff Goes Here...
a: 2

Bu, bir akış açma, akışa yazma ve güvenilir bir şekilde kapatma amacı için iki işlevin eşleştirilmesi ya da aralarında bazı işler yaptıktan sonra ikincisini çağırmayı unutamayacağınız şekilde eşleştirmek için faydalı olabilir. . Tabii ki, o kadar yeni ve sıradışı ki, başka bir programcı bir şeyi kırdıklarının farkında olmadan try bloğunu kaldırabilir, bu yüzden şu anda bir tür anti-patern, ama yapılabilmesi ilginç.

Zorunlu dillerdeki herhangi bir döngüyü özyineleme olarak ifade edebilirsiniz. Nesneler ve değişkenler değişmez yapılabilir. Yan etkileri en aza indirmek için işlemler yazılabilir (bir bilgisayarda gerçek bir fonksiyonun mümkün olmadığını iddia edersem - yürütülmesi için geçen süre ve tükettiği işlemci / disk / sistem kaynakları kaçınılmaz yan etkilerdir). Bazı işlevsel diller, hepsi nesne yönelimli işlemlerin tümü değilse bile birçok şey yapabilir. Bazı dillerin belirli kalıpları (değiştirilebilir alanlar gibi) önleyen kısıtlamaları olsa da (değişkenlerin güncellenmesine izin vermemek gibi) karşılıklı olarak dışlayıcı olmak zorunda değillerdir.

Bana göre, nesne yönelimli programlamanın en yararlı kısımları veri gizleme (enkapsülasyon), yeterince benzer nesnelere aynı şekilde (polimorfizm) davranmak ve verilerinizi ve bu veriler üzerinde birlikte çalışan yöntemleri (nesneler / sınıflar) toplamaktır. Kalıtım, OOP'un amiral gemisi olabilir, fakat benim için en az önemli ve en az kullanılan kısım.

İşlevsel programlamanın en kullanışlı kısımları değişmezlik (değişkenler yerine belirteçler / değerler), işlevler (yan etki yok) ve kapaklardır.

Nesne yönelimli olduğunu sanmıyorum, ancak bilgisayar bilimindeki en yararlı şeylerden birinin bir arabirim bildirme becerisi olduğunu ve sonra da bu işlevi uygulayan çeşitli işlevsellik ve verilere sahip olduğunu söylemeliyim. Ayrıca çalışacak birkaç değişken veriye sahip olmayı seviyorum, bu yüzden tüm program tasarımlarımdaki değişkenliği ve yan etkileri sınırlandırmaya çalışmama rağmen, sadece işlevsel dillerde tamamen rahat değilim.

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.