Dlaczego typLAB używa Haskella
Tłumaczenie: Why we use Haskell (Erik Hesselink)
Jako nowo utworzona spółka typLAB, mamy wiele decyzji technicznych do podjęcia. Jedną z ważniejszych jest wybór języka programowania. Ponieważ będziemy budować aplikacje webowe, więc wybór dotyczy zarówno klienta (czyli przeglądarki internetowej) jak i serwera.
Po stronie klienta nie ma wielu opcji, tam użyjemy JavaScript, chyba że chcielibyśmy zastosować Flash lub inną wtyczkę. Natomiast po stronie serwera mamy większą dowolność. Popularnym wyborem dla aplikacji webowych są dynamicznie typowane języki takie jak Ruby, Python czy PHP oraz statycznie typowane Java i C#.
Jednakże widzimy jeszcze inną możliwość. Dwóch z nas studiowało na kierunku Technologii Oprogramowania na Uniwersytecie w Utrechcie, gdzie często używaliśmy języka Haskell. Haskell jest językiem funkcyjnym co oznacza, że, w przeciwieństwie do języków imperatywnych, program składa się z wyrażeń a nie z instrukcji.
Jak już pewnie odgadłeś z tytułu, zdecydowaliśmy się na użycie Haskella po stronie serwera. Co nas do tego skłoniło?
Po pierwsze, lubimy funkcyjny model programowania. Modelowanie programów oparte o wartości zamiast o przerzucanie bitów po pamięci jest znacznie bliższe naszemu mentalnemu sposobowi myślenia. Po prostu piszemy co mamy w głowie a kompilator zajmuje się obliczeniami. To również skutkuje krótszym kodem: Haskell jest nadzwyczajnie zwięzły.
Następnym ważnym argumentem jest statyczny system typów Haskella. Jest on wystarczająco potężny, aby zapobiegać powstawaniu niepoprawnych programów a przy tym nie wchodzi programiście w drogę, jak to czasem się zdarza w tradycyjnych statycznie typowanych językach jak Java czy C#. Automatycznemu przypisywaniu typów zmiennych i funkcji nawet bez adnotacji programisty znacznie ułatwia pracę.
Haskell wyróżnia się spośród innych języków programowania swoją czystością: wyrażenie w Haskellu nie może robić nic innego jak tylko zwrócić swoją obliczoną wartość (funkcje nie mogą mieć efektów ubocznych). Dane są niemodyfikowalne: na przykład jeśli chcesz zmienić listę, tworzysz jej kopię (sprytne kompilatory będą współdzieliły jednakowe elementy). To znaczy, że nigdy nie ma strachu przed tym, że jakaś inna część programu zmieni nasze dane: można zawsze wnioskować tylko lokalnie. Jeszcze jednym plusem jest to, że język może być leniwy. Znaczy to, że wyrażenia nie są obliczanie do momentu, kiedy ich wartość będzie potrzebna. A to może prowadzić do zwiększenia wydajności z jednej strony a z drugiej pozwala na używanie nieskończonych struktur danych.
Jeśli zakażemy efektów ubocznych, to jak na przykład wykonać operacje wejścia wyjścia? Haskell do tego celu używa abstrakcji nazywanej monadą. Monada występuje w typie dając sygnał, że będziemy stosowali efekty uboczne. Monada wejścia wyjścia pozwala narzucić kolejność akcji, co pozwala bezpiecznie je wykonywać w leniwym języku. My używamy monad również do trzymania stanu, w związku ze zmiennymi i do wielu innych ciekawych rzeczy.
Czystość czyni też współbieżność dużo łatwiejszą: skoro dane są niemodyfikowalne, nie ma ryzyka przy współdzieleniu ich pomiędzy wątkami. Jeśli potrzebujesz współdzielić dane, Haskell umożliwia ci to na kilka sposobów, jedną z ciekawszych opcji jest programowa pamięć transakcyjna (STM), czyli bezzamkowy sposób na łączenie niepodzielnych akcji.
Ponieważ Haskell jest językiem funkcyjnym, funkcje są pełnoprawne: możesz je tworzyć w locie, możesz przekazywać je jako argumenty, zwracać jako wyniki czy umieszczać je w strukturach danych. To pozwala na proste tworzenie potężnych abstrakcji. Dla przykładu jedną z częściej używanych w Haskellu funkcji jest map. Przyjmuje ona jako argument inną funkcję przeliczającą wartość typu a na wartość typu b, a map używa jej do przeliczenia listy wartości typu a do listy wartości typu b, element po elemencie. Funkcja map abstrahuje więc iterację po liście. W podobny sposób możemy tworzyć własne abstrakcje. To często prowadzi to tworzenia języków lekkich (EDSL, embedded domain specific languages), szczególnie przydają się tutaj Haskellowe operatory infiksowe.
Połączenie zwięzłości, lokalności danych, silnych typów i formalnych efektów ubocznych ma bardzo ważna konsekwencję: zmiany stają się proste i bez ryzyka. Możesz zmieniać swój kod dowolnie i jeśli nadal przechodzi kontrolę typów, możesz być prawie pewien, że nadal działa poprawnie. W połączeniu z siłą abstrakcji umożliwia to nam szybkie tworzenie programów łatwych do zrozumienia i modyfikowania dla innych.
Na koniec dodajmy, ze bardzo pozytywnym aspektem Haskella jest grupa jego użytkowników. Istnieje sporo aktywnych blogów, duży i przyjazny kanał IRC (#haskell), dostępne w sieci repozytorium pakietów. Mamy świetny kompilator, menedżer pakietów oraz wiele wbudowanych narzędzi takich jak sprawdzanie pokrycia kodu.
Oczywiście z wyborem języka takiego jak Haskell wiąże się też pewne ryzyko. Ponieważ baza jego użytkowników nie jest tak duża jak niektórych innych języków, więc i dostępnych bibliotek jest mniej. Ale z tym sobie poradzimy, Haskell ma świetny interfejs do języka C. Z powodu leniwego trybu wykonywania problemy z wydajnością mogą być trudniejsze do zdiagnozowania i naprawy. No i oczywiście programistów Haskella jest mniej, więc znalezienie kogoś, kto może pomóc będzie nieco trudniejsze.
Bierzemy pod uwagę wszystkie za i przeciw i czujemy, że Haskell niesie ze sobą więcej korzyści niż zagrożeń. I najważniejsze: programowanie w Haskellu jest przyjemnością!