Czy Clojure da się lubić?

post_img

Po prezentacji Jacka Laskowskiego „Programowanie funkcjonalne funkcyjnie z Clojure praktycznie” na Infoshare 2011 wychodziliśmy z mieszanymi uczuciami. Powtarzał się pogląd o niedosycie informacji o tym nowym (dla mnie) języku. Korzystając z rozbudzonej ciekawości poznawczej, postanowiłem przyjrzeć się bliżej temu nawiasowemu językowi .

Powtarzając za Wikipedią, głównymi cechami języka są:

  • kompilowany do kodu bajtowego JVM (ang. Java Virtual Machine, wirtualna maszyna Javy);
  • pełna kompatybilność z Javą: Clojure natywnie wywołuje metody Javy i na odwrót;
  • możliwość pracy w trybie interaktywnym REPL (ang. read-eval-print loop, pętla wczytaj-wykonaj-wypisz);
  • domknięcia z naciskiem na rekurencję;
  • bogata biblioteka stałych struktur danych;
  • silne wsparcie dla współbieżności w postaci transakcyjnej pamięci (ang. Software Transactional Memory – STM) i systemu agentów.

Środowisko deweloperskie

Zacznijmy od instalacji środowiska pracy. Istnieją odpowiednie pluginy do większości popularnych IDE. Osobiście preferuję środowisko Eclipse, a więc do niego zainstalowałem plugin Counterclock. Po instalacji pluginu mamy między innymi funkcjonalność podpowiadania składni oraz okno REPL. REPL służy do dynamicznego programowania (o tym za chwilę).
Dodatkowo proponuję zainstalować środowisko Leiningen. Jest to środowisko uruchomieniowe Clojure — odpowiednik Maven w Javie. Sposób instalacji opisany jest na stronie projektu. Sprowadza się do pobrania aplikacji, rozpakowania pliku w katalogu docelowym i dodania ścieżki do zmiennej systemowej PATH. Następnie wydajemy polecenie lein self-install i to już wszystko. Lein automatycznie ściąga wszystkie niezbędne pakiety. Mała uwaga dotycząca sytuacji, w której jesteśmy za proxy. W pliku lein.bat dodajemy wiersze:

1
2
set http_proxy=http://server_proxy:port
set https_proxy=http://server_proxy:port

oraz modyfikujemy poniższy wiersz z:

1
set HTTP_CLIENT=wget --no-check-certificate -O

na:

1
set HTTP_CLIENT=wget --proxy-user=domena+login --proxy-password=hasło --no-check-certificate -O

Rozwiązuje nam to problem proxy.

Po instalacji otrzymujemy dostęp do interfejsu shellowego, w którym dostępnych jest wiele przydatnych akcji:

Dostępne są opcje rozwiązujące zależności (deps), kompilujące (compile) oraz oczywiście budujące (jar). Jednak jedną z najciekawszych funkcji jest możliwość rozszerzania funkcjonalności lein przez system pluginów. Jeden z nich to plugin generujący strukturę plików dla edytora Eclipse.
A więc po kolei:

  • tworzymy nowy projekt Clojure, wpisując polecenie lein new HelloWorldProject:
  • edytujemy wygenerowany plik D:\temp\HelloWorldProject\project\core.clj:
    1
    2
    3
    4
    5
    6
    7
    (defproject HelloWorldProject "1.0.0-SNAPSHOT"
    :description "FIXME: write description"
    :dependencies [[org.clojure/clojure "1.2.1"]]
    :dev-dependencies [
    [lein-eclipse "1.0.0"|lein-eclipse "1.0.0"]
    ]
    )
  • wydajemy polecenie lein deps — zostanie automagiczne ściągnięty plugin
  • wydajemy polecenie lein eclipse — zostają wygenerowane pliki .classpath i .project:
  • w Eclipsie importujemy project: File->Import…I gotowe! Projekt jest przygotowany do edycji w Eclipsie. Możemy rozpocząć programowanie.

    Składnia języka

Nie da się ukryć, że pierwszy kontakt ze składnią języka jest małym szokiem dla deweloperów Javy czy też C#. Za to programiści Lispa będą się czuć jak ryby w wodzie. Z tego właśnie języka pochodzi składnia języka. Najprościej rzecz ujmując, szablon wygląda następująco:

1
(polecenie argument argument)

Garść przykładów:

1
2
3
(println "Hello World"); — bez komentarza
(* 3 3); — wynik 9
(def zmienna (+ 2 (* 4 5))) — definicja zmiennej

Myślę, że nie ma sensu mnożyć tutaj przykładów, gdyż składnia jest bardzo szeroka, a jeszcze szersza jest baza tutoriali, przykładów oraz blogów na sieci. Ciekawsze propozycje zamieściłem na końcu tego artykułu w sekcji „Zasoby w sieci”.

Uruchomienie skryptu

Jest kilka możliwości uruchomienia skryptu. Wszystkie opierają się na rozwiązaniu REPL, czyli dynamicznym programowaniu. Daje ona np. możliwość ingerowania w kod działającej (nawet produkcyjnie) aplikacji. Potencjalnie możliwości są ogromne. Technicznie najprościej jest z poziomu Eclipsa wybrać edytowany skrypt *.clj i wydać komendę „Run”. Zostanie uruchomiona konsola REPL, kod skryptu zostanie załadowany i uruchomiony. Od tego momentu mamy dostęp do konsoli, w której możemy kontynuować kodowanie. Dynamiczność takiego programowania najłatwiej przedstawić na aplikacji swingowej. Poniższy kod uruchomi aplikację okienkową, w której podczas działania zmienimy rozmiar okna. To naprawdę działa, proszę sprawdzić!

  • import klasy JFrame
    1
    (import (javax.swing JFrame))
  • przypisanie do zmiennej f nowego obiektu klasy JFrame
    1
    (def f (JFrame. "Mój frame"));
  • uruchomienie metod pack i show na obiekcie f:
    1
    (doto f .pack .show)

    Efekt:

    A teraz uwaga! Program działa, a my w tym czasie zmienimy rozmiar okna:

    1
    (.setSize f 100 100)

    I oto wynik:

    Mała rzecz, a cieszy :).

    Podsumowanie

Siłą języka Clojure jest kompilacja do bajtkodu Javy. Dzięki temu może być wykorzystany w istniejących systemach jako zewnętrzna biblioteka. Inaczej mówiąc, Clojure nie oferuje nic więcej niż daje język Java. Za to udostępnia rozwiązania, których napisanie „ręcznie” w Javie zajęłoby wiele czasu i sprawiłoby niemały kłopot. Nie wspomniałem tu nic o wielowątkowości, która jest najsilniejszą stroną tego języka. Jest to podobno idealny język do pisania wielowątkowych aplikacji. Temat jest na tyle szeroki, że w celu jego omówienia można by napisać kolejny artykuł.

Zasoby w sieci

http://clojure.org/ — strona domowa
http://clojure.pl — polska strona domowa
http://java.ociweb.com/mark/clojure/article.html — świetny opis języka
http://clojars.org/ — baza danych o bibliotekach w Clojure
http://en.wikibooks.org/wiki/Clojure_Programming — wikibook o Clojure
http://www.learningclojure.com/
http://pramode.net/clojure/
http://www.clojureblog.pl/
http://loufranco.com/blog/files/category-20-days-of-clojure.html — 20 dni z Clojure


Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

2 komentarzy do “Czy Clojure da się lubić?

  • hubertus

    „Clojure nie oferuje nic więcej niż daje język Java.”
    Nie do końca, jedną z funkcjonalności, którą Java nie posiada (ze względów bezpieczeństwa) jest optymalizacja funkcji rekurencyjnych poprzez rekurencję ogonową (tail recursion), a w przypadku języka o paradygmacie funkcyjnym, rekurencja jest powszechnie stosowana.

  • hubertus

    „Clojure nie oferuje nic więcej niż daje język Java.”
    Nie do końca, jedną z funkcjonalności, którą Java nie posiada (ze względów bezpieczeństwa) jest optymalizacja funkcji rekurencyjnych poprzez rekurencję ogonową (tail recursion), a w przypadku języka o paradygmacie funkcyjnym, rekurencja jest powszechnie stosowana.

    „(def zmienna ( 2 (* 4 5))) — definicja zmiennej”
    W językach funkcyjnych nie ma pojęcia zmiennych, są tylko wartości nie mutowalne – widzę, że ten sam przykład pojawia się również w polskiej wersji Wikipedii.