Jakiś czas temu postanowiłem rozpocząć naukę kolejnego języka programowania. Tym razem padło na OCamla, będącego reprezentantem rodziny języków funkcyjnych (ściślej mówiąc, jest to język wieloparadygmatowy, a paradygmat funkcyjny jest jednym ze wspieranych). Dlaczego akurat OCaml, skoro istnieją inne, popularniejsze technologie z tej samej grupy? Mój wybór wynika z niezwykle dużej użyteczności OCamla na gruncie tworzenia kompilatorów. Jest to jeden z tych tematów, które budzą moją nieustanną ciekawość i rad byłbym zmierzyć się kiedyś z pisaniem kompilatora właśnie z tym języku, tak często polecanym i zbierającym dobre opinie w owej niszowej dziedzinie. Czytelnikom zainteresowanym tym zagadnieniem polecam przede wszystkim lekturę tekstu autorstwa Dwighta VandenBerghe’a Why ML/OCaml are good for writing compilers, a także dyskusji na Hacker News pełnej ciekawych przykładów, historii, linków i opinii.

Na początek kilka słów o samym języku, ponieważ nawet geneza jego nazwy oraz jej koneksje są dość interesujące. Nazwa OCaml była pierwotnie skrótem od Objective Caml. Historia jak wiele innych: istniał sobie (od połowy lat 80.) język Caml, ale czegoś mu brakowało – obiektowości – więc ktoś postanowił udoskonalić go o tę, nazwijmy to, funkcjonalność. I tu zaczyna się robić ciekawie, bowiem język Caml jest kategoryzowany jako dialekt języka ML (którego korzenie sięgają z kolei lat 70.). ML to inaczej Meta Language, można by się zatem spodziewać, że dwie ostatnie literki w nazwie Caml nawiązują właśnie do swojego rodzica. Tymczasem okazuje się, że oryginalne rozwinięcie to Categorical abstract machine language. Wniosek? Warto pamiętać, że mimo pokrewieństwa z językiem ML, OCaml wcale nie odziedziczył po nim „nazwiska”. 😉

REPL tak, ocaml nie

Czas jednak przejść do konkretów! Chcąc napisać swoje pierwsze OCamlowe „Hello world” potrzebujemy oczywiście kompilatora, który zamieni nasz kod na działający program. Sposobów na wyposażenie swojego systemu w kompilator OCamla jest kilka (do wyboru, do koloru), a ja, podobnie jak autorzy oficjalnej strony tego języka, rekomenduję skorzystanie z menadżera pakietów OPAM. Dzięki temu z łatwością zainstalujemy nie tylko samego OCamla, ale i odpowiednie biblioteki, których będziemy potrzebowali. Niezależnie od tego którą drogą podążyliśmy, finalnie wylądujemy z poleceniem ocaml, które możemy wywołać ze swojej konsoli. Jest to tzw. interactive toplevel, czyli środowisko REPL, w którym wprowadzany kod jest na bieżąco (tzn. po zatwierdzeniu go podwójnym średnikiem, o czym dokładniej będzie w następnym wpisie) kompilowany i ewaluowany, a rezultat tych działań prezentowany jest na ekranie. Innymi słowy, doskonałe środowisko do nauki i stawiania swoich pierwszych kroków w nowo poznawanym języku, czyż nie? No właśnie nie…

Toplevel ocaml jest sam w sobie niestety nad wyraz ubogi, do tego stopnia, że wiele osób prędzej zniechęci on do nauki OCamla, aniżeli zachęci. Oto przykłady jego braków:

  • Chcesz powtórzyć poprzednio wprowadzoną instrukcję? Naciśnięcie strzałki w górę z pewnością Ci nie pomoże!
  • Zrobiłeś błąd w aktualnie wprowadzanym wierszu? Musisz skasować wszystko aż do docelowego miejsca, gdyż manewrowanie lewo/prawo w obrębie wiersza nie jest tu możliwe.
  • Podpowiadanie skladni? Zapomnij!

Oczywiście istnieje kilka prostych tricków, które pozwalają rozwiązać problem edytowania linii, np. użycie edytora ledit: ledit ocaml albo zaprzęgnięcie do współpracy emacsa, ale najrozsądniejszym dla początkujących sposobem wydaje się być utop. Utop, czyli Universal Toplevel, to środowisko REPL zawierające poprawki, dzięki którym rzeczywiście można pokusić się o mówienie o przyjemności obcowania z OCamlem. Wspiera m.in. edytowanie linii, historię poleceń, autuzupełnianie składni oraz daje pewne możliwości personalizacji. Utop można zainstalować przy pomocy wspomnianego już menadżera pakietów OPAM (wpisując proste opam install utop).

Tak właśnie prezentuje się utop

Rozpoczynamy naukę

Ok, po przygotowaniu OCamlowego środowiska pracy jesteśmy już gotowi rozpocząć prawdziwą naukę. Nie mam zamiaru pisać tutoriali prezentujących od podstaw poszczególne elementy tego języka – istnieją już dobre i sprawdzone źródła, z których warto się uczyć. Wśród nich pozwolę sobie wymienić te, z których sam dość dużo korzystam:

  1. Real World OCaml – świetna i dość obszerna (ok. 500 stron) książka, będąca szczegółowym kursem języka OCaml. Można ją kupić, czy to w wersji papierowej, czy ebookowej, za kilkadziesiąt dolarów, a także… legalnie i bezpłatnie czytać na stronie internetowej RealWorldOcaml.org.
  2. Oficjalna strona OCamla (ocaml.org) to również bogate źródło wiedzy. Witryna rozwijana jest przez społeczność zgromadzoną wokół języka, a patrząc na commity na GitHubie widać, że aktualizacje pojawiają się często i regularnie. Wśród zgromadzonych zasobów znajdziemy m.in. zbiór odnośników do publikacji dotyczących OCamla oraz listę książek poświęconych temu językowi.
  3. Strona francuskiego instytutu badawczego INRIA (caml.inria.fr/ocaml), który jest producentem implementacji OCamla. Serwis ten nie jest już aktualizowany na bieżąco, ale zawiera wiele przydatnych materiałów, takich jak chociażby dokumentację sporej liczby modułów.

Polskojęzycznych materiałów jest niestety znacznie mniej – w internecie można znaleźć m.in. niedokończony kurs w Wikibooks oraz parę skryptów akademickich. Być może więc dla niektórych publikowane przeze mnie wpisy dotyczące OCamla stanowić będą pewne ułatwienie. Mam zamiar poruszać w nich te tematy, które dla mnie samego były czymś nieoczywistym, zaskakującym lub problematycznym podczas nauki, a zdobycie satysfakcjonujących informacji na ich temat wymagało dokonania syntezy kilku źródeł.

Niech się stanie zmienna

Pierwsza nieoczywistość – wszechobecne let i to, jak prawidłowo się nim posługiwać. Zrozumienie takiego zapisu:

nie jest rzecz jasna trudne. Tworzymy zmienną typu string o nazwie foo, przechowującą łańcuch znaków „bar”. var foo = "bar", czy też string foo = "bar" to jego odpowiedniki z innych języków. Ale co można powiedzieć na temat tego?

Gdy po raz pierwszy spotkałem się z taką instrukcją (oczywiście najpierw rzuciłem się do kodu, zamiast skrupulatnie pochłonąć pierwsze rozdziały tutoriali) odczytałem ją w sposób następujący:

co lekko mnie skonfundowało. Na szczęście, po przeanalizowaniu jeszcze kilku przykładów jasne okazało się, iż taką instrukcję należy rozumieć nieco inaczej:

Jeśli posłużymy się liczbami, np.:

łatwo można przetłumaczyć ów zapis na coś bardzo dobrze znanego nam ze szkolnej matematyki: „niech w wyrażeniu 2*x+3 wartość x będzie równa 10„.
Należy przy tym zauważyć, że taka instrukcja nie zapisuje obliczonego wyrażenia do żadnej zmiennej. Chcąc zapamiętać je np. w zmiennej x można by napisać:

Jeśli na pierwszy rzut oka uważasz, że taki zapis nie jest czytelny, to z pewnością ucieszy Cię fakt, iż równie poprawne semantycznie będą poniższe warianty:

Na szczęście już samo poprawne formatowanie kodu pozwala rozjaśnić sens tego typu instrukcji i nadaje im czytelność:

Innymi słowy, konstrukcja let name = expression in to tak naprawdę tworzenie zmiennych lokalnych. I choć można ją zapisać w nieco zawikłany sposób, to nie należy się jej bać, zwłaszcza iż w OCamlu spotkamy ją co krok.

Zachęta

Jeśli wciąż nie jesteś przekonany do instalowania tego całego bajzlu – opamów, utopów i nie wiadomo czego jeszcze, aby pobawić się OCamlem, możesz zapoznać się z kilkoma darmowymi lekcjami na wyposażonej w interaktywny interpreter stronie Try OCaml. Polecam!