Zauważyłem ostatnio, że funkcjonalne języki programowania zyskują popularność . Niedawno zobaczyłem, jak Indeks Tiobe pokazuje wzrost popularności w porównaniu do ubiegłego roku, chociaż większość z nich nawet nie osiąga 50 najpopularniejszych języków według tego indeksu.
Tak było od dłuższego czasu. Programowanie funkcjonalne po prostu nie stało się tak popularne jak inne modele (tj. Programowanie obiektowe).
Widziałem jednak odrodzenie zainteresowania siłą programowania funkcjonalnego, a teraz, gdy multikresy są coraz bardziej popularne, programiści zaczęli wykazywać zainteresowanie innymi modelami współbieżności, które już były badane w przeszłości przez języki takie jak Haskell i Erlang.
Z wielkim zainteresowaniem widzę, że pomimo braku znaczącej akceptacji społeczności, pojawia się coraz więcej takich języków. Clojure (2007), Scala (2003), F # (2002) to tylko trzy przykłady ostatniej dekady.
Sam poświęciłem trochę czasu na naukę Haskell i Scali. I znajduję wielki potencjał w paradygmacie, który dla mnie był nowy, mimo że byłam tam tak długo.
I oczywiście, moim największym pytaniem jest, czy któreś z nich stanie się na tyle popularne, aby rozważyć podjęcie jakiegokolwiek wysiłku, ale to pytanie, na które nawet Mandrake nie byłby w stanie odpowiedzieć, pomimo całego zamieszania, jakie ludzie o nim robią.
Chcę zapytać:
- W jakich scenariuszach powinienem rozważyć funkcjonalny język programowania, który lepiej nadaje się do wykonania danego zadania? Oprócz tak ostatnio popularnego problemu wielordzeniowego programowania równoległego.
- Gdybym zdecydował się na funkcjonalny język programowania, który uznałbyś za największe pułapki, z którymi się borykam? (Oprócz zmiany paradygmatu i trudności w ocenie wydajności z powodu leniwej oceny).
- Przy tak wielu funkcjonalnych językach programowania, jak wybrać ten, który najlepiej odpowiada Twoim potrzebom?
Wszelkie zalecenia dotyczące dalszych badań będą mile widziane.
Szukałem opinii w Internecie i wygląda na to, że cała ta odnowiona popularność wynika z pomysłu, że teraz uderzymy w ścianę Prawa Moore'a i nadejdą funkcjonalne języki programowania i bohatersko nas uratują. Ale jeśli tak jest, powiedziałbym, że istnieje większe prawdopodobieństwo, że istniejące popularne języki dostosują się do tego paradygmatu.
Być może niektórzy z was, z większym doświadczeniem w codziennej pracy z tymi językami, mogą uzyskać więcej informacji na ten temat. Wszystkie twoje opinie będą lepiej doceniane i uważnie przemyślane.
Z góry dziękuję!
Odpowiedzi:
Wszystko, co wymaga utworzenia sekwencji pochodnych elementów danych przy użyciu szeregu kroków transformacji.
Zasadniczo „problem z arkuszem kalkulacyjnym”. Masz pewne dane początkowe i zestaw obliczeń wiersz po rzędzie, które możesz zastosować do tych danych.
Nasze aplikacje produkcyjne wykonują szereg statystycznych podsumowań danych; do tego najlepiej podchodzić funkcjonalnie.
Jedną wspólną rzeczą jest łączenie trzech potwornych zestawów danych. Podobne do sprzężenia SQL, ale nie tak ogólne. Następnie następuje szereg obliczeń danych pochodnych. To wszystko tylko transformacje funkcjonalne.
Aplikacja została napisana w języku Python, ale została napisana w funkcjonalnym stylu, przy użyciu funkcji generatora i niezmiennych krotek nazwanych. To kompozycja funkcji niższego poziomu.
Oto konkretny przykład kompozycji funkcjonalnej.
Jest to jeden ze sposobów, w jaki programowanie funkcjonalne wpływa na języki takie jak Python.
Czasami tego rodzaju rzeczy są zapisywane jako:
Niezmienne przedmioty to najtrudniejsza przeszkoda.
Często kończysz obliczanie wartości tworzących nowe obiekty zamiast aktualizowania istniejących obiektów. Pomysł, że jest to zmienny atrybut obiektu, jest trudny do złamania.
Pochodna właściwość lub funkcja metody jest lepszym podejściem. Przedmioty stanowe są trudne do złamania.
Na początku to nie ma znaczenia. Wybierz dowolny język do nauki. Gdy już coś wiesz, możesz rozważyć wybranie innej, która będzie lepiej odpowiadać Twoim potrzebom.
Przeczytałem o Haskell, aby zrozumieć rzeczy, których brakuje w Pythonie.
źródło
„Funkcjonalny” to kilka różnych funkcji, z których każda jest niezależnie przydatna, i uważam, że bardziej przydatne jest spojrzenie na każdą z nich osobno.
Niezmienność
Teraz, gdy go znam, za każdym razem, gdy mogę uciec od niezmiennego wyniku, zawsze staram się to robić, nawet w programie zorientowanym obiektowo. Łatwiej jest wnioskować o programie, jeśli masz dane typu wartości. Zwykle potrzebujesz zmienności dla takich rzeczy jak GUI i wąskie gardła wydajności. Moje byty (używające NHibernate) są również zmienne (co ma sens, ponieważ modelują dane przechowywane w bazie danych).
Funkcje jako typy pierwszej klasy
Cokolwiek chcesz to nazwać, przekazywanie delegatów, działań lub funkcji, to naprawdę przydatny sposób na rozwiązanie całej klasy problemów w świecie rzeczywistym, takich jak „dziura w środku”. Przekonałem się również, że przekazanie delegata, akcji lub funkcji do obiektu jest czystsze niż to, że ta klasa deklaruje zdarzenie i przechwytuje to zdarzenie (zakładając, że zwykle jest tylko jeden „detektor”). Jeśli wiesz, że istnieje jeden detektor, wówczas akcja zwrotna może zostać przekazana jako parametr konstruktora (i zapisana w niezmiennym elemencie!)
Umiejętność komponowania funkcji (na przykład przekształcanie się
Action<T>
w po prostuAction
jest również przydatne w niektórych scenariuszach).Powinniśmy również zwrócić uwagę na składnię Lambda, ponieważ składnia Lambda jest dostępna tylko wtedy, gdy promujesz funkcje do typów pierwszej klasy. Składnia lambda może być bardzo ekspresyjna i zwięzła.
Monady
Wprawdzie jest to mój słaby punkt, ale rozumiem, że przepływy obliczeniowe w F #, takie jak
async
przepływ pracy, to monada. To subtelna, ale bardzo mocna konstrukcja. Jest tak silny, jakyield
słowo kluczowe używane do tworzeniaIEnumerable
klas w języku C #. Zasadniczo buduje on dla ciebie maszynę stanową, ale twoja logika wygląda liniowo.Leniwa ocena i rekurencja
Złożyłem je razem, ponieważ chociaż zawsze są one skupione jako funkcje programowania funkcjonalnego, tak szybko weszły w języki, które są konieczne, że trudno je nazwać funkcjonalnymi.
Wyrażenia S.
Myślę, że nie jestem pewien, gdzie to umieścić, ale możliwość traktowania nieskompilowanego kodu jako obiektu (i sprawdzania / modyfikowania go), takiego jak S-Expressions Lisp lub wyrażenia LINQ, jest pod pewnymi względami najpotężniejsze narzędzie programowania funkcjonalnego. Większość nowych „płynnych” interfejsów .NET i DSL używa kombinacji składni lambda i wyrażeń LINQ do tworzenia bardzo zwięzłych interfejsów API. Nie wspominając już o Linq2Sql / Linq2Nhibernate, gdzie twój kod C # jest „magicznie” wykonywany jako SQL zamiast jako kod C #.
To była długa odpowiedź na pierwszą część twojego pytania ... teraz ...
Największym problemem, z jakim się spotkałem, było znalezienie granicy między stosowaniem rozwiązań funkcjonalnych a koniecznymi. Jednak po kilkakrotnym wypróbowaniu obu podejść zaczynasz odczuwać, że będzie działać lepiej.
Jeśli znasz .NET, bardzo polecam F #. Z drugiej strony, jeśli jesteś bardziej zaznajomiony z JVM, zawsze jest Clojure . Jeśli jesteś bardziej akademicki niż praktyczny, wybrałbym Common Lisp lub Scheme. Jeśli znasz już Pythona, uważam, że dostępnych jest tam wiele funkcjonalnych konstrukcji.
źródło
Dzieje się tak, jeśli liczyć programy opracowane przez profesjonalnych programistów (lub przynajmniej osoby postrzegające siebie jako takie). Jeśli rozszerzysz swoją sieć o programy opracowane przez osoby, które nie uważają się za takie, FP (lub przynajmniej programowanie w funkcjonalnym stylu) jest dość zbliżone do OO (Excel, Mathematica, Matlab, R ... nawet „nowoczesny” JavaScript ).
Moim osobistym zdaniem jest to, że wielordzeniowość nie jest zabójczą funkcją FP (przynajmniej dopóki kompilatory Haskell, Scala, Clojure, F # nie rozwiążą problemu z lokalizacją pamięci podręcznej). Funkcja zabójca
map
,filter
,fold
i przyjaciół, które umożliwiają bardziej zwięzły wyraz dużej grupy algorytmów. Sytuację pogarszają języki FP o bardziej zwięzłej składni niż większość popularnych odpowiedników OO.Dodatkowo zbliżenie FP do modelu relacyjnego zmniejsza niedopasowanie impedancji z RDBMS ... co jest - co najmniej dla nie-programistów - bardzo miłe.
Również wtedy, gdy masz szczególnie trudne do spełnienia wymagania dotyczące „poprawności” - w formie, która jest trudna do przetestowania (powszechna w obliczeniach naukowych / analizie dużych danych, gdzie celem jest uzyskanie wcześniej nieznanych i jako takich nieokreślonych wyników) FP może zaoferować Zalety.
Ile problemów można rozwiązać, wychodząc już z bibliotek / frameworków na której platformie (np. JVM lub .Net), ile jest fabrycznie nowych? Czy istnieją konstrukcje językowe zdolne bezpośrednio wyrażać te problemy?
Ile kontroli niskiego poziomu potrzebujesz na przestrzeni i wydajności aplikacji?
Jak surowe są twoje wymagania dotyczące „poprawności”?
Czy stać Cię na przekwalifikowanie programistów i / lub konkurowanie z korzyściami oferowanymi przez niektóre wysoce dochodowe nisze w rozwoju SW?
źródło
Zakładając, że jesteś programistą C ++ / C # / Java w branży ...
Bądź przygotowany na zrzędliwych rówieśników, którzy nie chcą się niczego uczyć. Przygotuj się na spiczastych szefów narzucających złe wybory językowe „ponieważ kiedyś byli programistami”. Przygotuj się na żwawych naukowców na forach protekcjonujących cię w sprawie monoidów. Przygotuj się na niekończące się wojny językowe, ponieważ Scala nawet nie eliminuje ogonów, a Clojure naprawdę wymaga pedałów dla wszystkich nawiasów i nie zaczynaj od Erlanga.
Jeśli jesteś programistą internetowym, największą pułapką będą prawdopodobnie twoje włosy.
Zacznę od platformy:
źródło
Dla jednej (co prawda stronniczej) perspektywy na to pytanie, możesz sprawdzić blog Boba Harpera, Existential Type . Carnegie Mellon niedawno przerobiła swój program CS, aby uczyć najpierw programowania funkcjonalnego, a inne paradygmaty są nauczane dopiero po ustaleniu solidnego podstaw programowania funkcjonalnego, a Harper daje cios, gdy nowy program nauczania jest wdrażany w praktyce .
Harper jest jednym z głównych twórców standardowego języka programowania ML, więc można śmiało powiedzieć, że jego własne zdanie na ten temat można z góry zgadnąć, a on z pewnością nie boi się kontrowersyjnych stwierdzeń argumentujących za tym stanowiskiem, ale czyni jego sprawa dobrze.
źródło
var
ani razu nie użyłem ani żadnej kolekcji podlegającej modyfikacji. Tak więc imperatywne myślenie jest IMO pewnego rodzaju przedwczesną optymalizacją, która, jak wszyscy wiemy, jest źródłem wszelkiego zła.Nie ma magicznej formuły, która podpowiada, kiedy używać programowania funkcjonalnego. To nie jest tak, że programowanie obiektowe lepiej pasuje do naszych obecnych sytuacji programistycznych. To po prostu inny sposób konstruowania programów pod względem innego zestawu abstrakcji.
Programowanie funkcjonalne nie ma nic wspólnego z lenistwem. ML i OCaml są funkcjonalnymi i ścisłymi językami. Największą przeszkodą, jaką napotkasz, jest konstruowanie rzeczy w kategoriach niezmiennych wartości i zawijanie głowy wokół jakiejkolwiek abstrakcji używanej w systemie typów do efektów ubocznych. Języki funkcjonalne lepiej nadają się do optymalizacji, ponieważ powodują, że skutki uboczne są bardzo wyraźne w systemie typów. Haskell używa monad, ale istnieją inne podejścia do używania efektów w czysto funkcjonalnych językach. Clean ma typy unikatowości, a niektóre inne języki w fazie rozwoju mają inne rzeczy.
Wśród znanych mi języków programowania powiedziałbym, że tylko Haskell i Clean można nazwać językami funkcjonalnymi. Wszystkie pozostałe pozwalają na efekty uboczne bez wyraźnego zaznaczania tych efektów w systemie typów. Jeśli więc zamierzasz poświęcić czas na naukę programowania funkcjonalnego, to Haskell jest prawdopodobnie jedynym, który pasuje do tego rachunku. Wszystkie pozostałe, które znam, Erlang, Scala, Clojure, itp. Zapewniają funkcjonalne abstrakty na imperatywnym języku. Więc jeśli chcesz podejść do paradygmatu funkcjonalnego w bitach, poleciłbym Scalę lub Erlanga, a jeśli chcesz poradzić sobie ze wszystkim naraz i być może zrezygnować z frustracji, powinieneś iść z Haskellem.
źródło
Obecny wzrost zainteresowania językami funkcjonalnymi przypisałbym temu, że są one idealne do obliczeń równoległych. Na przykład cała idea zmniejszania mapy opiera się na paradygmacie funkcjonalnym. I nie ma wątpliwości, że równoległe obliczenia będą rosły, ponieważ jest oczywiste, że obecnie skalowanie jest o wiele łatwiejsze i tańsze niż skalowanie. Nawet na rynku konsumenckim procesory mają więcej rdzeni, a nie więcej GHz.
EDYCJA: ponieważ nie jest to oczywiste dla wszystkich.
W czystym programowaniu funkcjonalnym funkcja pobiera dane wejściowe, wytwarza dane wyjściowe i nie wywołuje żadnych skutków ubocznych. Brak efektu ubocznego oznacza, że nie ma on wspólnego stanu, a zatem nie ma potrzeby mechanizmów synchronizacji, które w innym przypadku byłyby konieczne podczas jednoczesnego działania. Synchronizacja jest najtrudniejszą częścią każdego oprogramowania współbieżnego / równoległego, dzięki czemu jest czysto funkcjonalna, w zasadzie nie musisz zajmować się najtrudniejszą częścią.
Jeśli chodzi o redukcję map, nawet nazwa pochodzi od programowania funkcjonalnego (zarówno mapowanie, jak i redukcja to typowe operacje w paradygmacie funkcjonalnym). Oba etapy zmniejszania mapy są funkcjami, które działają równolegle, pobierają dane wejściowe, generują dane wyjściowe i nie mają skutków ubocznych. Jest to więc dokładnie pomysł programowania funkcjonalnego.
Kilka przykładów FP wykorzystanych do równoległości:
źródło