Programowanie funkcjonalne a programowanie obiektowe [zamknięte]

783

Do tej pory byłem głównie narażony na programowanie OO i nie mogę się doczekać nauki funkcjonalnego języka. Moje pytania to:

  • Kiedy wybierasz programowanie funkcjonalne zamiast obiektowego?
  • Jakie są typowe definicje problemów, w których programowanie funkcjonalne jest lepszym wyborem?
Olivier Lalonde
źródło
to jest odpowiedni programmers.stackexchange.com/questions/9730/…
kirill_igum 11.09.2013
1
podobne pytanie cs.se również zamknęło przykład, w którym programowanie funkcjonalne daje lepsze wyniki niż styl imperatywny . konwencjonalna mądrość wydaje się polegać na tym, że jedno nie jest lepsze od drugiego, lub że nie można ich porównywać na podstawie prostych kryteriów, lub że są one wykorzystywane do różnych celów ... programowanie funkcjonalne ma więcej naukowych / akademickich źródeł i zastosowań i jest mniej powszechne w przemyśle , więc pytanie ustanawia również nierozwiązywalny pow / konflikt „przemysł kontra uczelnie”. jeden klasyczny ref, który pokazuje system OOP w programowaniu funkcjonalnym, książka SICP / MIT
od
OO sprawia, że ​​kod jest zrozumiały, zamykając ruchome części. FP sprawia, że ​​kod jest zrozumiały przez minimalizację ruchomych części. ” --Micheal Feathers, 2010
jaco0646

Odpowiedzi:

1192

Kiedy wybierasz programowanie funkcjonalne zamiast obiektowego?

Gdy spodziewasz się innego rodzaju ewolucji oprogramowania:

  • Języki zorientowane obiektowo są dobre, gdy masz ustalony zestaw operacji na rzeczach , a wraz z rozwojem kodu dodajesz przede wszystkim nowe rzeczy. Można to osiągnąć przez dodanie nowych klas, które implementują istniejące metody, a istniejące klasy pozostawia się w spokoju.

  • Języki funkcjonalne są dobre, gdy masz stały zestaw rzeczy , a wraz z ewolucją kodu dodajesz przede wszystkim nowe operacje na istniejących rzeczach. Można to osiągnąć przez dodanie nowych funkcji, które obliczają z istniejącymi typami danych, a istniejące funkcje są pozostawione same sobie.

Kiedy ewolucja idzie w złym kierunku, masz problemy:

  • Dodanie nowej operacji do programu obiektowego może wymagać edycji wielu definicji klas w celu dodania nowej metody.

  • Dodanie nowego rodzaju rzeczy do programu funkcjonalnego może wymagać edycji wielu definicji funkcji, aby dodać nowy przypadek.

Problem ten jest dobrze znany od wielu lat; w 1998 roku Phil Wadler nazwał to „problemem ekspresji” . Chociaż niektórzy badacze uważają, że problem z ekspresją można rozwiązać za pomocą takich cech językowych, jak mixiny, powszechnie akceptowane rozwiązanie nie znalazło się jeszcze w głównym nurcie.

Jakie są typowe definicje problemów, w których programowanie funkcjonalne jest lepszym wyborem?

Języki funkcjonalne przodują w manipulowaniu danymi symbolicznymi w formie drzewa. Ulubionym przykładem są kompilatory, w których języki źródłowy i pośredni zmieniają się rzadko (głównie te same rzeczy ), ale autorzy kompilatorów zawsze dodają nowe tłumaczenia i ulepszenia lub optymalizacje kodu (nowe operacje na rzeczach). Kompilacja i tłumaczenie są bardziej „zabójczymi aplikacjami” dla języków funkcjonalnych.

Norman Ramsey
źródło
119
Za tą odpowiedzią kryje się poważny zen. Myślę, że to uwidacznia fakt, że pewne wzorce projektowe OOP (Visitor) są w rzeczywistości hackami, które próbują przezwyciężyć problem dodawania nowych operacji.
Jacobs Data Solutions
54
W JavaScript możesz mieć wszystkie rzeczy.
Erik Reppen
61
@ErikReppen, w którym momencie pojawia się pytanie, kiedy decydujesz się na użycie funkcji funkcjonalnych, a kiedy na funkcję obiektową?
Norman Ramsey,
7
@NormanRamsey Nie jest niczym niezwykłym mieszanie go w JS, a pierwszorzędne funkcje są powiązane z wieloma funkcjami związanymi z OS JS. Sortowanie tablic JS przyjmuje funkcje jako argument, który może wytworzyć potężne struktury danych. Zamknięcia + przekazana funkcja służy do utrzymywania obiektów jquery bardzo lekkich pod względem pamięci, ponieważ większość metod jest tylko referencjami. Itd ...
Erik Reppen
9
@NormanRamsey: Bardzo dobra odpowiedź, zgodna z SICP. Zgodnie z tą klasyfikacją programowanie funkcjonalne i proceduralne jest zgrupowane po przeciwnej stronie programowania obiektowego. To może wyjaśnić boom OOP pod koniec lat 80. na początku lat 90.: kiedy GUI stały się głównym nurtem, OOP okazało się dobrym podejściem do modelowania ich, ponieważ zwykle masz ustalony zestaw operacji (malowanie, otwieranie, zamykanie, zmiana rozmiaru) i rosnąca liczba widżetów. Oczywiście nie oznacza to, że OOP jest lepszy niż proceduralny dla dowolnej aplikacji, jak zilustrowałeś.
Giorgio,
176

Niekoniecznie musisz wybierać między tymi dwoma paradygmatami. Możesz pisać oprogramowanie z architekturą OO, używając wielu koncepcji funkcjonalnych. FP i OOP mają charakter ortogonalny .

Weźmy na przykład C #. Można powiedzieć, że jest to głównie OOP, ale istnieje wiele koncepcji i konstrukcji FP. Jeśli wziąć pod uwagę Linq , najważniejsze konstrukcje, które pozwalają na istnienie Linq, mają charakter funkcjonalny: wyrażenia lambda .

Kolejny przykład, F #. Można powiedzieć, że jest to głównie FP, ale dostępnych jest wiele koncepcji i konstrukcji OOP. Możesz definiować klasy, klasy abstrakcyjne, interfejsy, zajmować się dziedziczeniem. Zmienności można używać nawet wtedy, gdy kod jest bardziej przejrzysty lub gdy znacznie zwiększa wydajność.

Wiele współczesnych języków jest paradygmatem.

Zalecane odczyty

Ponieważ jestem na tej samej łodzi (tło OOP, uczę się FP), zasugeruję Ci kilka lektur, które naprawdę doceniam:

Bruno Reis
źródło
8
@duffymo: Twój komentarz, jak to ująłeś, jest w większości bezcelowy. Dziękuję, nikt nie chce porównywania języków, maszyn wirtualnych lub platform.
Bruno Reis,
6
@Bruno - odpowiedź na „moc .NET”. Zrelaksować się.
duffymo
6
Zabawne, nie widzę, jak krytykujesz Dykama za jego bezsensowny komentarz. Czy byłeś nominowany na moderatora, kiedy ja nie szukałem? Nikt tu nie pali, oprócz ciebie. Powiem to jeszcze raz - zrelaksuj się.
duffymo
4
Heh, przepraszam, jeśli zacząłem płonąć. Nie chciałem powiedzieć, że inne platformy są mniej wydajne, po prostu .NET nie obsługuje tylko OOP. Na przykład ma optymalizację wywołania ogona.
Dykam
5
@nawfal, dopóki nie możesz wskazać pewnych nieodłącznych cech w dwóch paradygmatach i powiedzieć, że są one niezgodne, są ortogonalne: to jest sedno dyskusji. FP jest z definicji niekompatybilny z programowaniem imperatywnym, ale OOP nie ogranicza się do programowania imperatywnego. Powodem, dla którego mamy różne słowa na temat tych pojęć, jest to, że możemy o nich porozmawiać: kiedy je złączysz, zmuszasz nas do niepotrzebnego wymyślania nowych słów.
DavidS
31

Programowanie obiektowe oferuje:

  1. Encapsulation, to
    • kontrola mutacji stanu wewnętrznego
    • ograniczenie sprzężenia do reprezentacji wewnętrznej
  2. Subtyping, umożliwiający:
    • podstawienie kompatybilnych typów (polimorfizm)
    • prymitywny sposób dzielenia się implementacją między klasami (dziedziczenie implementacji)

Programowanie funkcjonalne, w Haskell, a nawet w Scali, może pozwolić na podstawienie poprzez bardziej ogólny mechanizm klas typów. Zmienny stan wewnętrzny jest albo odradzany, albo zabroniony. Można również osiągnąć enkapsulację reprezentacji wewnętrznej. Dobre porównanie patrz Haskell vs OOP .

Twierdzenie Normana, że ​​„Dodanie nowego rodzaju rzeczy do programu funkcjonalnego może wymagać edycji wielu definicji funkcji w celu dodania nowego przypadku”. zależy od tego, jak dobrze kod funkcjonalny zastosował klasy typów. Jeśli dopasowanie wzorca dla określonego abstrakcyjnego typu danych jest rozłożone w bazie kodu, rzeczywiście będziesz cierpieć z powodu tego problemu, ale być może jest to kiepski projekt na początek.

ZMIENIONO Usunięto odniesienie do niejawnych konwersji podczas omawiania klas typów. W Scali klasy typów są kodowane za pomocą parametrów niejawnych, a nie konwersji, chociaż konwersje niejawne są kolejnym sposobem uzyskania substytucji kompatybilnych typów.

2 obroty
źródło
3
Klasy typów nie stanowią mechanizmu niejawnej konwersji na inne typy. Są opisem zestawu funkcji zdefiniowanych dla typu, aby zapewnić formę polimorfizmu. Najbliższą rzeczą w OOP w stylu Java byłyby interfejsy, chociaż typy Haskell mają pewne ważne różnice.
Zak
25
  1. Jeśli pracujesz w silnie współbieżnym środowisku, przydatne jest programowanie czysto funkcjonalne. Brak stanu zmiennego czyni współbieżność prawie banalną. Zobacz Erlang.

  2. W języku multiparadygmatu możesz chcieć modelować niektóre rzeczy funkcjonalnie, jeśli istnienie stanu zmiennego jest szczegółem implementacyjnym, a zatem FP jest dobrym modelem dla dziedziny problemowej. Na przykład zobacz opisy list w języku Python lub std.range w języku programowania D. Inspirowane są one programowaniem funkcjonalnym.

dsimcha
źródło