Im bardziej funkcjonalne programowanie, tym bardziej czuję, że dodaje dodatkową warstwę abstrakcji, która wydaje się, że warstwa cebuli obejmuje wszystkie poprzednie warstwy.
Nie wiem, czy to prawda, więc odejście od zasad OOP, nad którymi pracowałem od lat, może ktoś wytłumaczyć, jak funkcjonalne dokładnie przedstawia lub nie przedstawia żadnej z nich: enkapsulacja, abstrakcja, dziedziczenie, polimorfizm
Myślę, że wszyscy możemy powiedzieć, tak, ma on hermetyzację za pomocą krotek, czy krotki liczą się pod względem technicznym jako „programowanie funkcjonalne”, czy są one tylko użytecznością języka?
Wiem, że Haskell może spełnić wymóg „interfejsów”, ale znowu nie jesteś pewien, czy jego metoda jest funkcjonalna? Zgaduję, że fakt, że funktory mają podstawy matematyczne, można powiedzieć, że są to określone wbudowane oczekiwania dotyczące funkcjonalności?
Proszę szczegółowo opisać, w jaki sposób funkcjonalność spełnia lub nie spełnia 4 zasad OOP.
Edycja: Rozumiem różnice między paradygmatem funkcjonalnym a paradygmatem zorientowanym obiektowo i doskonale zdaję sobie sprawę z tego, że w dzisiejszych czasach istnieje wiele języków wieloparadygmatu, które mogą to zrobić. Naprawdę szukam tylko definicji tego, jak bezpośredni fp (myśl purysta, jak haskell) może zrobić jedną z 4 wymienionych tu rzeczy lub dlaczego nie może zrobić żadnej z nich. tzn. „Kapsułkowanie można wykonać przy zamknięciach” (lub jeśli się mylę w tym przekonaniu, proszę podać powód).
źródło
Odpowiedzi:
Programowanie funkcjonalne nie jest warstwą powyżej OOP; to zupełnie inny paradygmat. Możliwe jest wykonywanie OOP w funkcjonalnym stylu (F # został napisany właśnie w tym celu), a na drugim końcu spektrum masz rzeczy takie jak Haskell, który wyraźnie odrzuca zasady orientacji obiektowej.
Możesz wykonywać enkapsulację i abstrakcję w dowolnym języku wystarczająco zaawansowanym, aby obsługiwać moduły i funkcje. OO zapewnia specjalne mechanizmy enkapsulacji, ale nie jest to coś nieodłącznego dla OO. Punktem OO jest druga wspomniana para: dziedziczenie i polimorfizm. Pojęcie to jest formalnie znane jako podstawienie Liskowa i nie można go uzyskać bez wsparcia na poziomie programowania programowania obiektowego. (Tak, w niektórych przypadkach można go sfałszować, ale tracisz wiele zalet, które OO przynosi do stołu.)
Programowanie funkcjonalne nie koncentruje się na podstawieniu Liskowa. Koncentruje się na zwiększeniu poziomu abstrakcji oraz na zminimalizowaniu użycia stanu zmiennego i procedur z „efektami ubocznymi”, co jest terminem, który programiści funkcjonalni lubią używać do tworzenia procedur, które faktycznie coś robią (w przeciwieństwie do zwykłego obliczania czegoś) straszny. Ale znowu są to zupełnie odrębne paradygmaty, których można używać razem, lub nie, w zależności od języka i umiejętności programisty.
źródło
Uważam, że poniższa intuicja jest przydatna do porównywania OOP i FP.
Zamiast rozważać FP jako nadzbiór OOP, pomyśl o OOP i FP jako dwóch alternatywnych sposobach spojrzenia na podobny bazowy model obliczeniowy, w którym masz:
W OOP jest to rejestrowane przez
W FP jest to uchwycone przez
Dzięki tej interpretacji obiekt może być postrzegany jako zbiór zamknięć (jego metod), z których wszystkie przechwytują te same zmienne nielokalne (zmienne składowe obiektu wspólne dla wszystkich zamknięć w kolekcji). Ten widok jest również wspierany przez fakt, że w językach obiektowych zamknięcia są często modelowane jako obiekty przy użyciu dokładnie jednej metody.
Myślę, że różne punkty widzenia wynikają z faktu, że widok zorientowany obiektowo jest wyśrodkowany na obiektach (danych), podczas gdy widok funkcjonalny jest wyśrodkowany na funkcjach / zamknięciach (operacjach).
źródło
To zależy od tego, kogo poprosisz o definicję OOP. Zapytaj pięć osób, a prawdopodobnie otrzymasz sześć definicji. Wikipedia mówi :
Tak więc, gdy ktoś udzieli bardzo ostatecznej odpowiedzi, weź ją z odrobiną soli.
To powiedziawszy, istnieje dobry argument, że tak, FP jest nadzbiorem OOP jako paradygmatu. W szczególności definicja programowania obiektowego Alana Kaya nie jest sprzeczna z tym pojęciem (ale Kristen Nygaard ). Kay była naprawdę zaniepokojona tym, że wszystko jest przedmiotem, a logika jest realizowana poprzez przekazywanie komunikatów między obiektami.
Być może bardziej interesujące dla twojego pytania, o klasach i obiektach można myśleć w kategoriach funkcji i zamknięć zwracanych przez funkcje (które działają jednocześnie jako klasy i konstruktory). Jest to bardzo zbliżone do programowania opartego na prototypach, a JavaScript pozwala na to dokładnie.
(Oczywiście JavaScript pozwala na mutowanie wartości, które są nielegalne w czysto funkcjonalnym programowaniu, ale nie jest również wymagane w ścisłej definicji OOP.)
Ważniejsze pytanie brzmi jednak: czy jest to znacząca klasyfikacja OOP? Czy pomocne jest myślenie o nim jako o podziale programowania funkcjonalnego? Myślę, że w większości przypadków tak nie jest.
źródło
FP jak OO nie jest dobrze zdefiniowanym terminem. Istnieją szkoły o różnych, czasem sprzecznych definicjach. Jeśli weźmiesz to, co ich łączy, przejdziesz do:
programowanie funkcjonalne to programowanie z funkcjami pierwszej klasy
Programowanie OO to programowanie z polimorfizmem inkluzyjnym połączeniu z co najmniej ograniczoną formą dynamicznie rozwiązywanego przeciążenia. (Uwaga dodatkowa: w kręgach OO polimorfizm zazwyczaj oznacza polimorfizm inkluzyjny , podczas gdy szkoły FP zwykle oznaczają polimorfizm parametryczny ).
Wszystko inne jest obecne gdzie indziej lub w niektórych przypadkach nieobecne.
FP i OO to narzędzie do budowania dwóch abstrakcji. Każdy z nich ma swoje mocne i słabe strony (na przykład mają inny preferowany kierunek rozszerzenia w problemie ekspresji), ale żaden z nich nie jest z natury silniejszy od drugiego. Możesz zbudować system OO na jądrze FP (CLOS jest jednym z takich systemów). Możesz użyć frameworka OO, aby uzyskać funkcje pierwszej klasy (zobacz na przykład sposób definiowania funkcji lambda w C ++ 11).
źródło
std::function
do którego można przypisać zarówno wskaźniki funkcji, jak i lambdy, jest zdecydowanie ogólny, a nie obiektowy. Nie jest to niespodzianką, ponieważ ograniczony rodzaj polimorfizmu orientacji obiektowej (polimorfizm podtypu) jest ściśle mniej silny niż polimorfizm parametryczny (nawet Hindley-Milner, nie mówiąc już o pełnym Systemie F-omega).Nie; OOP może być postrzegany jako nadzór programowania proceduralnego i różni się zasadniczo od paradygmatu funkcjonalnego, ponieważ ma stan reprezentowany w polach instancji. W paradygmacie funkcjonalnym zmienne są funkcjami, które są stosowane do stałych danych w celu uzyskania pożądanego wyniku.
W rzeczywistości można rozważyć programowanie funkcjonalne jako podzbiór OOP; jeśli sprawisz, że wszystkie twoje klasy będą niezmienne, możesz pomyśleć, że masz jakieś funkcjonalne programowanie.
źródło
Odpowiedź:
Wikipedia ma świetny artykuł na temat programowania funkcjonalnego z niektórymi przykładami, o które prosisz. @Konrad Rudolph podał już link do artykułu OOP .
Nie sądzę, że jeden paradygmat jest super-zestawem drugiego. Są to różne perspektywy programowania i niektóre problemy można lepiej rozwiązać z jednej perspektywy, a niektóre z drugiej.
Twoje pytanie jest jeszcze bardziej skomplikowane przez wszystkie implementacje FP i OOP. Każdy język ma swoje dziwactwa, które są istotne dla każdej dobrej odpowiedzi na twoje pytanie.
Coraz bardziej styczne wędrowanie:
Podoba mi się pomysł, że język taki jak Scala stara się dać ci to, co najlepsze z obu światów. Martwię się, że daje to również komplikacje obu światów.
Java jest językiem OO, ale w wersji 7 dodano funkcję „spróbuj z zasobami”, której można użyć do naśladowania pewnego rodzaju zamknięcia. Tutaj imituje aktualizację lokalnej zmiennej „a” w środku innej funkcji, nie czyniąc jej widoczną dla tej funkcji. W tym przypadku pierwsza połowa drugiej funkcji to konstruktor ClosureTry (), a druga połowa to metoda close ().
Wydajność:
Może to być przydatne do zamierzonego celu, jakim jest otwarcie strumienia, zapisanie do strumienia i niezawodne zamknięcie go, lub po prostu sparowanie dwóch funkcji w taki sposób, aby nie zapomnieć o wywołaniu drugiej po wykonaniu jakiejś pracy między nimi . Oczywiście jest to tak nowe i niezwykłe, że inny programista może usunąć blok try, nie zdając sobie sprawy, że coś psuje, więc jest to obecnie rodzaj anty-wzorca, ale interesujące, że można to zrobić.
Możesz wyrazić dowolną pętlę w większości imperatywnych języków jako rekurencję. Obiekty i zmienne można uczynić niezmiennymi. Procedury mogą być napisane w celu zminimalizowania skutków ubocznych (chociaż twierdzę, że prawdziwa funkcja nie jest możliwa na komputerze - czas potrzebny do wykonania i zużycie procesora / dysku / systemu to nieuniknione skutki uboczne). Niektóre języki funkcjonalne mogą być przystosowane do wykonywania wielu, jeśli nie wszystkich operacji obiektowych. Nie muszą się wzajemnie wykluczać, chociaż niektóre języki mają ograniczenia (np. Nie zezwalające na aktualizację zmiennych), które uniemożliwiają określone wzorce (jak zmienne pola).
Dla mnie najbardziej użytecznymi częściami programowania obiektowego są ukrywanie danych (enkapsulacja), traktowanie wystarczająco podobnych obiektów jako takich samych (polimorfizm) oraz gromadzenie danych i metod, które działają na tych danych razem (obiekty / klasy). Dziedziczenie może być okrętem flagowym OOP, ale dla mnie jest to najmniej ważna i najmniej używana część.
Najbardziej przydatne części programowania funkcjonalnego to niezmienność (tokeny / wartości zamiast zmiennych), funkcje (bez skutków ubocznych) i zamknięcia.
Nie sądzę, że jest zorientowany obiektowo, ale muszę powiedzieć, że jedną z najbardziej przydatnych rzeczy w informatyce jest możliwość deklarowania interfejsu, a następnie posiadania różnych funkcji i danych implementujących ten interfejs. Lubię też mieć kilka zmiennych danych do pracy, więc wydaje mi się, że nie czuję się całkowicie komfortowo w wyłącznie funkcjonalnych językach, chociaż staram się ograniczać zmienność i efekty uboczne we wszystkich projektach mojego programu.
źródło