Poczytaj mi Clojure – podręcznik

“Poczytaj mi Clojure” to podręcznik programowania w jednym z najbardziej elastycznych i ekspresywnych języków służących do komunikacji człowieka z maszyną.

Clojure jest stworzonym przez Richa Hickeya dynamicznie typizowanym dialektem języka Lisp ogólnego przeznaczenia, którego wzorcowa implementacja działa pod kontrolą maszyny wirtualnej Javy (ang. Java Virtual Machine, skr. JVM). Poza formalizmem, siłą wyrazu i zwięzłością Lispa mamy pełen dostęp do ekosystemu Javy, możemy więc korzystać zarówno z wewnętrznych klas i ich metod, jak i z wielu dodatkowych, zewnętrznych bibliotek.

Clojure to przede wszystkim język funkcyjny (większość konstrukcji to funkcje lub elementy zachowujące się jak funkcje), chociaż dzięki ścisłej integracji z Javą i możliwościom operowania na obiektach możemy go nazwać językiem wieloparadygmatowym. Zaprojektowany został z myślą o wykonywaniu współbieżnym (ang. concurrent), a w praktyce cel ten zrealizowano wprowadzając trwałe (ang. persistent) struktury danych, w oparciu o które obsługiwane są dane niemutowalne (ang. immutable) – niezmienne struktury znajdujące zastosowanie w większości wykonywanych operacji. Kiedy jednak zachodzi konieczność wyrażania stałych tożsamości, których stany mogą się zmieniać do dyspozycji jest kilka tzw. typów referencyjnych.

Od jakiegoś czasu Clojure znajduje zastosowanie w programowaniu zastosowań sieciowych, na przykład przy budowaniu webowych serwisów czy API. Stąd też rosnące zainteresowanie nim, szczególnie wśród wczesnych zwolenników (ang. early adopters), m.in. tych, którzy programują również w Pythonie, Rubym, F# czy Javie.

Rozdziały

Poniżej znajdują się odnośniki do kolejnych rozdziałów wraz z krótkimi opisami tematycznymi:

  • Rozdział I: Lisp

    Podstawowe informacje o historii i cechach języka Lisp, którego dialektem jest Clojure. Poznasz podstawowe konstrukcje języka (listy, atomy, symbole, S-wyrażenia i formuły), dowiesz się też dlaczego wcześniej Lispy nie były tak popularne, a teraz świętują swą drugą młodość.

  • Rozdział II: Stan, tożsamość i zmiana

    Informacje o najważniejszych różnicach między paradygmatem imperatywnym a funkcyjnym z objaśnieniami bazującymi na koncepcjach twórcy Clojure, z których korzystał opracowując język. Rozdział ten zawiera też opis terminów używanych w odniesieniu do pamięciowych struktur danych – wyjaśnia m.in. czym jest powiązanie, wartość, stan i zmienna globalna.

  • Rozdział III: Pierwsze kroki

    Praktyczne wskazówki dotyczące instalacji i pracy z interaktywną pętlą REPL, a także omówienie wyrażeń warunkowych: if, cond, when i case. Przy okazji omawiania REPL wyjaśniony jest również krok po kroku proces wartościowania symbolicznych wyrażeń, z których składają się programy.

  • Rozdział IV: Struktury danych

    Rozdział ten opisuje podstawowe struktury i typy danych języka: symbole, klucze, wartości logiczne, liczby, znaki i łańcuchy znakowe. Każdy typ jest omówiony i zilustrowany funkcjami, które operują na bazujących na nim wartościach.

    • Rozdział IV A: Typy danych

      Typy danych pozwalają klasyfikować wartości pod względem różnych cech i wykształcać relacje między tak powstałymi klasami. Programiście pomaga to generalizować lub uszczegóławiać operacje przeprowadzane na danych, a mechanizmom języka zarządzać pamięcią i wykrywać niektóre rodzaje błędów. W Clojure mamy do czynienia z kilkoma powiązanymi ze sobą systemami typów, które możemy rozszerzać, a wykorzystując ich polimorficzne mechanizmy jesteśmy w stanie abstrahować zarządzanie danymi i budować ujednolicone interfejsy wymiany informacji.

  • Rozdział V: Przestrzenie nazw i powiązania

    Powiązania umożliwiają korzystanie z wartości i typów referencyjnych przez identyfikowanie ich przypisanymi, symbolicznymi nazwami. Z kolei przestrzenie nazw są strukturami, które umożliwiają zarządzanie widocznością identyfikatorów. W rozdziale tym zawarto wiedzę dotyczącą rodzajów zasięgu, widoczności i identyfikacji obiektów umieszczanych w pamięci.

  • Rozdział VI: Zmienne globalne i typ Var

    Zmienne globalne to podstawowy typ referencyjny języka Clojure, dzięki któremu można tworzyć stałe tożsamości o zmiennych stanach. W praktyce służy nazywaniu funkcji, globalnych wartości (np. ustawień konfiguracyjnych aplikacji), innych obiektów referencyjnych, a także do tworzenia dynamicznego zasięgu identyfikatorów.

  • Rozdział VII: Funkcje i domknięcia

    Czym byłby język funkcyjny bez funkcji? W rozdziale tym pokazany jest mechanizm definiowania i korzystania z funkcji (zarówno nazwanych, jak i anonimowych), a także wyjaśnione jest znaczenie tzw. domknięć.

  • Rozdział VIII: Kolekcje

    Kolekcje to abstrakcyjna klasa struktur danych języka Clojure, służąca do porządkowania i zarządzania zbiorami informacji. W rozdziale dowiesz się więcej o korzystaniu z kolekcji, poznasz też wbudowane kolekcje języka, takie jak listy, wektory, mapy i zbiory.

  • Rozdział IX: Sekwencje

    Sekwencje to przypominające iteratory, abstrakcyjne listy z następczym interfejsem dostępu do elementów. Nie są typową strukturą danych, lecz sposobem reprezentowania zbiorów informacji, który cechuje zachowywanie porządku sąsiadujących elementów. W Clojure wiele operacji polega na dostępie sekwencyjnym, którego można używać w odniesieniu do wbudowanych kolekcji i innych złożonych typów danych wyposażonych w sekwencyjny interfejs.

  • Rozdział X: Komparatory

    Komparatory to funkcje, które służą do porównywania elementów kolekcji i/lub sekwencji. Są wykorzystywane przede wszystkim w operacjach sortowania. W Clojure każda funkcja może być komparatorem, jeżeli tylko będziemy przestrzegali odpowiednich wytycznych.

  • Rozdział XI: Pętle i rekurencja

    Niektóre funkcje i problemy mogą być czytelnie wyrażone w postaci rekurencyjnej lub zapętlonej. W Clojure istnieją konstrukcje, które pozwalają implementować algorytmy w taki właśnie sposób.

  • Rozdział XII: Współbieżność

    Wykonywanie współbieżne pozwala spożytkować moc obliczeniową więcej niż jednego procesora lub rdzenia, pomaga też w lepszym zarządzaniu czasem obliczeniowym, gdy niektóre operacje muszą oczekiwać na obsługę komunikacji międzyprocesowej lub podsystemu wejścia/wyjścia. Clojure proponuje przejrzystą i wygodną implementację wykonywania współbieżnego, wykorzystującą typy referencyjne i programową pamięć transakcyjną.

    • Rozdział XII A: Atomy

      Atom to typ referencyjny przeznaczony do obsługi danych przetwarzanych współbieżnie, do których wymagany jest nieskoordynowany, synchroniczny dostęp. Możemy dzięki niemu tworzyć proste i ”lekkie” współdzielone obiekty, wyrażające zmieniające się stany (np. liczniki czy odpowiedniki semaforów).

    • Rozdział XII B: Agenty

      Agent typ referencyjny podobny do Atomu. Dzięki niemu można wyrażać nieskoordynowane zmiany stanów współdzielonych tożsamości w asynchroniczny sposób. Wykorzystywane są na przykład do obsługi kolejek komunikatów i innego rodzaju wymiany informacji między niezależnie działającymi komponentami.

    • Rozdział XII C: Referencje transakcyjne

      Ref to typ referencyjny, dzięki któremu można wyrażać częste i jednoczesne zmiany stanów wielu współdzielonych tożsamości w synchroniczny sposób. Wykorzystywany jest tam, gdzie kilka wartości wskazywanych przez referencje zależy od siebie i modyfikacja ich wszystkich powinna być atomowa (np. przekazywanie środków między rachunkami bankowymi). Do obsługi Refów intensywnie wykorzystywana jest programowa pamięć transakcyjna (STM).

    • Rozdział XII D: Wątki

      Korzystanie z dodatkowych wątków i sterowanie wykonywaniem bieżącego pozwalają precyzyjnie zarządzać współbieżnym realizowaniem zadań. W Clojure możemy w tym celu użyć dodatkowych typów referencyjnych: Future, PromiseDelay. Istnieją również odpowiednie klasy Javy realizujące podobne cele, a nawet typ Volatile, który pozwala tworzyć szybkie choć niebezpieczne odpowiedniki zmiennych.

  • Rozdział XIII: Transduktory

    Transduktory to funkcje, które służą do przekształcania funkcji redukujących. Pozwalają one na tworzenie kolejnej warstwy abstrakcji, dzięki której można implementować transformacje wieloelementowych struktur danych niezależne od ich konkretnych charakterystyk.

  • Rozdział XIV: Makra

    Makra to jeden z mechanizmów metaprogramowania – zbioru technik umożliwiających odczytywanie, tworzenie i modyfikowanie programów przez inne programy lub przez nie same. Są one jedną z charakterystycznych cech dialektów języka Lisp. Pozwalają przekształcać kod źródłowy programu zanim dojdzie do jego ewaluacji i stwarzać nowe konstrukcje składniowe. Dzięki nim jesteśmy w stanie nie tylko rozszerzać możliwości języka, ale nawet budować tzw. języki dziedzinowe, dostosowane do wyrażania specyficznych problemów i ich rozwiązań.

  • Rozdział XV: Polimorfizm

    Polimorfizm to zbiór mechanizmów, dzięki którym te same konstrukcje mogą być używane w odniesieniu do danych różnych rodzajów. Dzięki niemu możemy przetwarzać informacje z użyciem wyabstrahowanych, generycznych operacji, zyskując na czasie i czytelności kodu. Polimorfizm w Clojure to przede wszystkim obsługa wieloargumentowości, multimetod, protokołów i rekordów, a także korzystanie z obiektowego systemu typów platformy gospodarza.

Od autora

Podręcznik ten był pierwotnie notatkami tworzonymi na potrzeby własne, pomocnymi w procesie nauki języka. Pierwsze zapiski umieszczałem w serwisach społecznościowych, a po kilku tygodniach postanowiłem zadbać o strukturę i formę, publikując treści w reaktywowanym z tej okazji blogu.

Mam nadzieję, że samouczek przyda się każdemu, kto chce poznać Clojure i spróbować funkcyjnego stylu programowania. Nawet jeśli ten konkretny język nie okaże się strzałem w dziesiątkę, jeśli chodzi o potrzeby praktycznych zastosowań, to z pewnością jego znajomość rozwinie lepsze umiejętności kodowania we wszystkich innych.

Dotychczas stworzony materiał podzielony jest na części (dokumenty hipertekstowe), a każda z tych części zawiera przynajmniej jeden rozdział, poświęcony konkretnemu zagadnieniu ogólnemu. Podręcznik nie jest jeszcze kompletny, a w tym miejscu będę dodawał nowe rozdziały w miarę ich powstawania.

Nota prawna

“Poczytaj mi Clojure” jest utworem w rozumieniu prawa autorskiego i zastrzegam sobie do niego wszelkie prawa. Póki co nie zgadzam się na powielanie, rozpowszechnianie i publiczne wykonywanie. Może kiedyś zdecyduję się uwolnić część lub całość, albo wydać w innej formie.

Umieszczam ten podręcznik w Sieci, ponieważ pisanie nie jest moim głównym sposobem zarabiania na utrzymanie, a marże wydawnictw i dystrybutorów są za duże, żeby na tę chwilę opłacało mi się z nimi współpracować. Moim marzeniem jest, aby ten zbiór tekstów zawierał więcej wiedzy, niż każda wydana w języku polskim książka o Clojure, którą możesz kupić.

Komentarze