Co to jest?Część NR.1Programowanie funkcyjne istnieje od bardzo długiego czasu. Język programowania LISP w 1958 roku postawił punkt startowy w programowaniu funkcjonalnym. Z drugiej strony LISP już wtedy bazował na koncepcjach, które istniały. Pierwsze kroki w kierunku programowania funkcjonalnego można datować na lata 1930-1940. Wtedy Alonzo Vhruch opracował lambda Calcus.
http://en.wikipedia.org/wiki/Lambda_calculus*
Co to jest programowanie Funkcyjne
Programowanie funkcje jest kolejnym paradygmatem programowania, który występuje w wielu językach programowania. Jak sama nazwa wskazuje koncentruje się na funkcjach.
Dla niektórych programistów programowanie funkcyjne wydaje się być naturalne. Funkcyjne programowanie według nich bardziej koncentruje się na problemie, który powinien być rozwiązany niż na poszczególnych krokach rozwiązania problemu.
Wynika to z wysokiego poziomu abstrakcji jakie programowanie funkcjonale zapewnia. Jedyną specyfikacją dla programisty jest właśnie funkcja lub ich zestaw.
Komputer może później ocenić, jaka kolejność jest najlepsza, dodać możliwość wielowątkowości albo zadecydować, czy dana funkcja musi zostać wykonana.
Brzmi to skomplikowanie. Programowanie funkcyjne może nie być dobrym punktem startowym w nauce programowania, lub w ogóle może okazać się za trudne.
Zrozumienie programowania funkcyjnego też nie jest łatwe dla programistów z doświadczeniem w zakresie języków programowania obiektowego i proceduralnego.
Mimo wszystko, ja właśnie postanowiłem rozszerzyć swoją wiedzę na ten temat. Mógłbym zacząć od nauki jakiegoś języka funkcyjnego , ale stwierdziłem, że zacznę swoją przygodę w obserwacji, jak C#, który jest językiem obiektowym implementuje aspekty programowania funkcjonalnego.
Związek z językiem obiektowym
Dzisiaj wiele języków programowania jest hybrydami. Nie koncentrują się one na jednym sposobie programowania: obiektowe, funkcyjne.
Tylko mieszają jedno z drugim.
Obiektowo zorientowane programowanie koncentruje się na hermetyzacji, łączeniu danych i zachowań w formie klas i obiektów oraz definiowaniu interfejsów.
Te pomysły pomagają w modelowaniu świata rzeczywistego na świat komputerowy. Wiele aplikacji biznesowych koncentruje się na przechowywaniu danych, które zazwyczaj reprezentują rzeczywisty obiekt, który ma właściwości.
W rezultacie obiektowo zorientowane języki programowania są łatwe do zrozumienia.
Kiedy jednak spojrzymy na skomplikowane równania i algorytmy wtedy będziemy starać się modelować kod jako kolekcję kół zębatych. Jest to wtedy abstrakcyjny system, do którego wrzucamy dane, a z drugiej strony wychodzi nam końcowy produkt.
Zastanawiam się wtedy nad tym, co tak naprawdę nasza maszyna robi, gdy uruchamiamy ten mechanizm kół zębatych. Nagle się okazuje, że cała obiektowość nam niezbyt ułatwia to zadanie i tracimy czas, i wydajność programu na zbędne operacje.
Wtedy na ratunek przychodzi programowanie funkcyjne.
W rzeczywistości oba punkty widzenia są potrzebne. Programowanie nie zawiera złotych środków na każdy problem. Programiści powinni zrozumieć różnicę pomiędzy tymi technikami i używać ich w odpowiedni sposób.
Większość programów składa się z części, w których modelowanie danych jest istotne. W innych programach algorytm jest najważniejszy. W innych programach nie ma takiego jawnego podziału.
Dlatego wiele języków programowania, w tym C# są hybrydami. Nie jest to zupełnie nowy pomysł, pierwszym takim językiem Common Lisp.*
W dzisiejszym świecie w platformie .NET mamy do dyspozycji wiele hybryd. C# wraz z wersją szóstą podejmuje coraz to bardziej ambitne kroki w kierunku programowania funkcyjnego
Język F# bardzo wpływa na decyzje językowe w C#. C# 7.0 będzie trochę dziwny.
Funkcyjne programowanie w kontekście C#
Programowanie podzieliło się na dwie ścieżki. Jedni zajęli się programowaniem funkcyjne i dostali odpowiednie języki programowania i narzędzia do tego.
Później programowanie funkcyjne zostało odsunięte trochę na bok. Wielkie firmy, jak Microsoft skoncentrowały się na aplikacjach biznesowych. Powstały więc języki i narzędzia zorientowane w tym kierunku.
Po latach ci z programowania obiektowego zdali sobie sprawę, że wiele ich problemów zostało już rozwiązanych lata temu, po stronie innej szkoły programowania.
Jakie są więc powody tego, że wiele języków programowania mutuję się w stronę programowania funkcyjne.
Otóż wcześniej procesory rozwijały coraz to większe prędkości. W pewnym momencie jednak procesory napotkały na szklany sufit, na granicę prędkości, która nie może zostać pokonana.
Aby zwiększyć szybkość działania komputera, obecnie zwiększamy liczbę procesorów.
Programy jednak by z tego skorzystać muszą działa wielowątkowo. Microsoft w tym celu wypuścił bibliotekę Parallel Extensions jak i wprowadził słowa kluczowe async i await oraz klasę TASK.
Niestety pojawił się tutaj problem związany ze strukturą samego języka programowania. Normalny styl obiektowy dzieli i zmienia dużo informacji na temat swojego stanu. To może spowodować prawdziwy ból głowy w aplikacji wielowątkowej.
Programowanie obiektowe wymusza na programiście zasadę o przetrzymywaniu danych i informacji, które mogą zostać uzyskane przez wiele metod lub funkcji.
Nawet z biblioteką Parallel Extensions ciężko jest napisać taką aplikację, bo sam język nie został napisany z myślą o wielowątkowości.
Dla przykładu istnieje metoda “Paraller.ForEach” , która robi to samo, co standardowe słowo kluczowe foreach w c# tyle, że spodziewa się równoległej egzekucji .
To jednak zadziała jeśli kod wewnątrz pętli jest odpowiednio ustrukturyzowany tak, aby nie było kolizji dostępu do danych.
Efekty uboczne i ich zarządzanie
W programowaniu funkcyjnym.
Czy jest efekt uboczny ?
Efekt uboczny występuje właśnie wtedy, gdy wiele metod lub funkcji w programie musi dzielić tą samą informację. Co najważniejsze nie tylko tą informację dzieli, ale także ją zmienia.
Jedną z głównych idei w programowaniu funkcyjnego jest właśnie zarządzanie efektem ubocznym.
Oznacza to, że ten problem będziemy trochę zwalczać.
Całkowite rozwiązanie tego problemu byłoby iluzją. Komputer nie może wyświetlić czegoś na ekranie, przetrzymywać jakiś danych, czy wysłać coś przez sieć bez efektu ubocznego.
Mówiąc bardziej po ludzku, komputer gdzieś musi się zsynchronizować.
Jest to trochę problematyczne. Chociaż może wydawać się to proste. Gdy jeden wątek zmienia pewną informację, to inny powinien poczekać.
Problem pojawia się, gdy mamy wiele informacji, które są rozproszone wszędzie i są one powiązane z pewnymi operacjami. Ciężko jest określić wszystkie scenariusze przenikania, więc najprościej umieścić w tych miejscach blokady oparte na flagach. Mechanizm kolejki też tutaj się przydaje.
W programowaniu funkcyjnym programiści uczą się, jak inaczej poradzić sobie z tym problemem. Sam język ma inną strukturę, więc sposoby na ten problem są lepsze.
Oczywiście języki funkcyjne nie mają wszystkich odpowiedzi na problemy wielowątkowości . Nie zmienia to jednak faktu, że jest to właśnie główny powód, dla którego języki funkcyjne przenikają do innych języków i stają się coraz to bardziej popularne.
Modularność funkcji
Po wielowątkowości przychodzi kolejne ciekawe zagadnienie, jakim jest modularność funkcji. Co to znaczy?
Każda funkcja składa się z części. Każda część powinna być potraktowana jak moduł.
W obiektowym języku programowania występują klasy i wewnątrz danej klasy mamy metody. Wiele języków programowania daję możliwość utworzenia zagnieżdżonych metod.
W C# nie jest to możliwe. (przynajmniej gdy pisałem ten wpis edit:2020)
Myśląc obiektowo, tak byś mógł osiągnąć swój cel. Nie obędzie się jednak bez klasy zagnieżdżonej.
public class ContainingClass
{
public static class NestedClass
{
public static void Method2()
{
}
public static void Method3()
{
}
}
}
Jednak nam bardziej chodzi o coś takiego.
public static void Method1()
{
var method2 = new Action(() => { /* action body */ } );
var method3 = new Action(() => { /* action body */ } );
//call them like normal methods
method2();
method3();
//if you want an argument
var actionWithArgument = new Action<int>(i => { Console.WriteLine(i); });
actionWithArgument(5);
//if you want to return something
var function = new Func<int, int>(i => { return i++; });
int test = function(6);
}
Źródło kodu: http://stackoverflow.com/questions/8135050/method-within-a-method
Używając delegat i anonimowych metod możemy już podzielić naszą metodę na części.
Ten styl programowania pasuje, gdy wiele osób pracuje nad częścią danego algorytmu. Dla programisty obiektowego może wydawać się to dziwne, ale dla programistów funkcyjnych jest to chleb powszedni.
Programowanie deklaratywne
Funkcyjne programowanie jest generalnie traktowane jako programowanie deklaratywne. Programowanie deklaratywne koncentruje się na określonym celu i logice. Co powinien program robić. Co jego część powinna robić.
Wszystko to określić bez opisywania kroków, które są potrzebne do osiągnięcia celu.
O detalach decyduje komputer, np. jak program powinien być uruchamiany.
Jakie mamy przykłady programowania deklaratywnego.
- Języki domenowe jak HTML,XML, XAML są językami, które opisują dokumenty i dane w nich zawarte.
- Wyrażenia regularne, które opisują złożone informację na temat tego, jaka informacja powinna być przetworzona.
- Języki zapytań jak SQL , włączając w to zapytania LINQ.
Funkcjonalne programowanie jest mniej specyficznym typem deklaratywnego programowania w zestawieniu z poprzednimi przykładami.
Nie zmienia to jednak faktu, że idee w nim takie istnieją.
Programowanie funkcyjne to stan umysłu
Przychodząc na spotkanie na temat programowania funkcyjnego , w pewnym momencie zdałem sobie sprawę z bardzo ważnej rzeczy.
Programowania funkcyjne to stan umysłu.
Z tego powodu dla kogoś, kto już ma doświadczenie z językami obiektowymi, moim zdaniem ciężko jest nauczyć się języków z tego spektrum. Python, Ruby, F#, Scala, Haskell
Dlatego pomyślałem sobie, dlaczego więc nie zacząć od prostego kursu na temat jak programujemy funkcyjne w C#.
Zwłaszcza, że C# w wersji 6.0 i 7.0 idzie w kierunku programowania funkcyjnego.
Czy programowanie funkcyjne w C# to dobry pomysł
Gdy ma się młotek wszystko wydaje się gwoździem.
Czy Języki programowania powinny być postrzegane jako uniwersalne narzędzie do rozwiązywania wszystkich problemów.
W F# mogę zrobić stronę w ASP.NET MVC - czemu nie.
Czy języki programowania może powinny być postrzegane raczej jak skalpele do konkretnych zadań i delikatnych problemów.
Praktyczne zrozumienie różnic pomiędzy językami programowania oraz konsekwencji ich użycia bardziej zbliża nas do drugiego, “czy” ze skalpelem.
W końcu jeśli chcesz napisać kod funkcyjny , to wyjdzie ci to najlepiej, pisząc w języku funkcyjne.
W rzeczywistość chodzi o kompromis.
Jeśli twoja drużyna umie pisać kod w C#, to nagle jedna osoba nie napisze aplikacji w F# bo jest to skalpel do tego zadania. Musi być jakaś konsystencja w projektach w firmie.
Z drugiej strony programiści, którzy się ograniczają do jednego języka, wkrótce zobaczą, że są inne sposoby na rozwiązywanie ich problemów.
Młotek i skalpel reprezentują skrajności.
Kurs programowania funkcyjnego w C# czas zacząć:
Czy jest sens programować funkcyjnie w C#?
Tak.
Zobaczmy więc, jak możemy wykorzystać te pozytywne aspekty, by pisać lepszy kod.