piątek, 9 listopada 2007

Procesory wielordzeniowe a programowanie

Miesiąc temu obiecałem napisać o rewolucji w sposobie myślenia o pisaniu programów. Zdradziłem wtedy, że chodzi o język Haskell. Czym więc jest Haskell? Jest językiem programowania (to raczej nie jest niespodzianka) o następujących cechach:
  1. czysto funkcyjny - o ile programowanie funkcyjne jest samo w sobie diametralnie innym podejściem do tworzenia oprogramowania, to dopiero "czysta" funkcyjność Haskella jest prawdziwym unikatem, o którym za chwilę
  2. funkcje jako wartości podstawowe - funkcje mogą być parametrami lub wartościami wynikowymi innych funkcji
  3. currying funkcji - w największym skrócie chodzi o to, że podając np. dwuparametrowej funkcji "dodaj" jeden parametr (np. 3), otrzymujemy w rezultacie nową funkcję jednoparametrową (którą można by nazwać "dodaj3do")
  4. z silną i statyczną kontrolą typów - nie zamierzam bynajmniej rozpoczynać tu dyskusji o wyższości świąt Bożego narodzenia na świętami Wielkiejnocy (w wydaniach "silna czy słaba" / "statyczna czy dynamiczna" kontrola typów), zawsze sugeruję użycie najbardziej odpowiedniego narzędzia w określonej sytuacji
  5. z odgadywaniem typów - interpreter lub kompilator potrafi (w zdecydowanej większości przypadków) poprawnie "odgadnąć" typ wyrażenia, więc programista nie musi go jawnie deklarować; tak przy okazji, to połączenie statycznej kontroli typów z ich odgadywaniem typów jest bardzo dobrym rozwiązaniem, bo pozwala ograniczyć charakterystyczną dla statycznie typowanych języków "rozwlekłość" kodu
Wyjaśnienia wymaga przede wszystkim "czystość" podejścia funkcyjnego zastosowana w Haskellu. Autorzy języka trzymają się ściśle definicji funkcji wyniesionej z dziedziny, która dała nam funkcje - matematyki. Jednym z założeń funkcji jest to, że nie może wpływać ona na otoczenie oraz to, że dla danego parametru wejściowego zawsze daje ten sam wynik. Takiego założenia nie spełnia np. najprostsza "funkcja" (można by ją dla uniknięcia niejednoznaczności określić jako "procedura") pobierania znaku z klawiatury - getChar. Wiele innych języków funkcyjnych przymyka na ten fakt oko i nie robi z tego powodu żadnego problemu. Haskell idzie krok dalej i, korzystając z bardzo abstrakcyjnego działu matematyki zwanego teorią kategorii, wprowadza wyraźny podział na właściwe funkcje (spełniające wymagania definicji funkcji) oraz monady (nie wiem niestety czy to poprawne polskie określenie, równie złe ale dające pewien punkt odniesienia to "akcje"). O tym czym są monady w kontekście języka Haskell pewnie jeszcze napiszę przy okazji (to ulubiony temat blogów o Haskellu), na razie powinna wystarczyć informacja, że Haskell rozróżnia funkcje i akcje.

Całe to zamieszanie z czystością podejścia funkcyjnego raczej odstrasza niż zachęca. Dlaczego więc twórcy Haskella tak się przy tym upierają? Jakie korzyści może to przynieść? I co to wszystko ma wspólnego z tematem posta - procesorami wielordzeniowymi?

Własności funkcji matematycznej - funkcja zawsze da ten sam wynik dla określonego parametru i nigdy nie wpłynie na wywołanie innej funkcji - sprawiają, że jej zastosowanie w programie komputerowym daje potężne możliwości optymalizacji dla kompilatora lub interpretera. Nie ma też żadnego ryzyka związanego z uruchomieniem np. 32 współbieżnych wątków obliczających dowolną funkcję (czego nie można powiedzieć o uruchomieniu chociażby 2 współbieżnych wątków dokonujących modyfikacji w systemie plików). A nie ma lepszej metody na wykorzystanie coraz bardziej popularnych procesorów wielordzeniowych niż aplikacje wielowątkowe.

Chwila - wielu czytelników zapewne teraz zwróci uwagę - aplikacje wielowątkowe to przecież żadna nowość. Zaletą podejścia w Haskellu jest jednak to, że jawnie oddzielone są od siebie bezpieczne bloki kodu (gdzie bezpieczeństwo oznacza "możliwość wpływania na swoje otoczenie") od potencjalnie niebezpiecznych.

Brak komentarzy: