Clojure
![]() Logo języka | |
Pojawienie się | |
---|---|
Paradygmat | |
Typowanie | |
Aktualna wersja stabilna |
1.12.0 |
Twórca | |
Licencja | |
Platforma sprzętowa | |
Platforma systemowa | |
Strona internetowa |

Clojure (ⓘ[2]) – nowoczesny dialekt języka programowania Lisp opracowany przez Richa Hickeya. Jest to język ogólnego przeznaczenia, wspierający modyfikację uruchomionego programu i zachęcający do programowania funkcyjnego oraz współbieżnego.
Clojure akcentuje niezmienność struktur danych jako kluczową technikę ułatwiającą programowanie współbieżne. Działa na wirtualnej maszynie Javy. Może być uruchamiany przez interpreter lub kompilowany do kodu bajtowego. Można w nim tworzyć aplety, aplikacje lub serwlety, co umożliwia tworzenie aplikacji internetowych w całości w języku Clojure. Cały język mieści się w jednym pliku jar. Ma rozbudowany system makr znany z Lispu, dzięki czemu można rozszerzać język o nowe konstrukcje. Posiada jedną przestrzeń nazw dla funkcji i zmiennych tak jak Scheme. Posiada pełną integrację z językiem Java, można uruchamiać kod Clojure z poziomu Javy, jak i kod Javy z poziomu Clojure.
Etymologia nazwy
Nazwa Clojure pochodzi od słowa Closure (domknięcie), które jest ważnym elementem języka Lisp, z literą s zamienioną na j, wskazująca Javę. Autor chciał utworzyć nazwę, która nawiązywałaby do C#, Lispa i Javy[2] i to właśnie dlatego wybrał to słowo na nazwę swojego języka programowania.
Niektóre cechy języka
- 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)[3] i systemu agentów;
- Zwięzły kod w porównaniu z innymi językami[4].
Przykłady
Uruchomienie REPL
java -cp clojure.jar clojure.main
Wypisywanie tekstu
(println "Hello world!")
Definicja zmiennej globalnej
Zmienne globalne to umieszczone w mapie zwanej przestrzenią nazw odwzorowania symboli na obiekty typu Var. Te ostatnie są typem referencyjnym, który przechowuje odniesienia do wartości umieszczanych w pamięci (np. liczb, łańcuchów tekstowych, obiektów funkcyjnych czy innych rezultatów obliczeń). Zmienne globalne są sposobem nadawania nazw rzadko lub wcale nie zmieniającym się stanom abstrakcyjnych obiektów wyrażających różne wartości na przestrzeni czasu (funkcje, elementy konfiguracji, stałe wartości).
Dzięki konstrukcji def
można stworzyć globalne powiązania symboli z wartościami za pośrednictwem obiektów typu Var.
(def wynik (+ 2 (* 4 5)))
Definicja funkcji
Funkcja obliczająca silnie (nazwy zmiennych tj. symboli, tak jak w innych dialektach języka lisp mogą się składać z dowolnych znaków).
(defn ! [x]
(if (= x 0)
1
(* x (! (- x 1)))))
Funkcje anonimowe
Funkcja anonimowa czy funkcja bez nazwy, można przekazać całe poniższe wyrażenie jako argument do innej funkcji (taka funkcja będzie więc funkcją wyższego rzędu).
(fn [x] (* 2 (/ 3 4)))
Czyli funkcje które przyjmują inne funkcje jako argumenty lub zwracają funkcje.
(defn f [x]
(* 2 (/ 3 4)))
(map f '(3 4 5 6 7 8))
Lub to samo używając funkcji anonimowej:
(map (fn [x] (* 2 (/ 3 4))) '(3 4 5 6 7 8))
Funkcja zwracająca anonimową funkcję
(defn f [x]
(fn [] x))
Powyższa funkcja zwraca funkcję anonimową, która z kolei zwraca zmienną przekazaną jako argument do tej pierwszej funkcji, jest to tzw. domknięcie leksykalne.
Makra
Makra tak jak w innych dialektach lispa przetwarzają przekazane wyrażenia, bez wcześniejszego obliczania jak w przypadku funkcji, w całości jako listę. Poniżej makro define służące do definiowania funkcji jak w Scheme.
(defmacro define [params & body]
`(defn ~(first params) [~@(rest params)] ~@body))
(define (f x) (* x x))
(f 10)
W odróżnieniu od innych dialektów, do obliczenia wyrażenia wewnątrz cytowania Quasi-quotation, zamiast przecinka używa się znaku tyldy.
Tworzenie nowego obiektu Javy
(new java.lang.String "Hello world!")
Wywoływanie metody obiektu
(defn upper [s] (.toUpperCase s))
(upper (new java.lang.String "foo bar"))
Wywoływanie metody statycznej
Funkcja string->integer
występująca w języku Scheme.
(defn string->integer
([str]
(Integer/parseInt str 10))
([str base]
(Integer/parseInt str base)))
GUI
Użycie biblioteki Swing.
(javax.swing.JOptionPane/showMessageDialog nil "Hello world!")
Zobacz też
Przypisy
- ↑ Rich Hickey: Pierwszy rok Clojure'a. 2008-10-16. [dostęp 2016-02-20]. (ang.).
- ↑ a b Rich Hickey: Znaczenie i wymowa „Clojure”. 2009-01-05. [dostęp 2016-02-20]. (ang.).
- ↑ Bedra i Halloway 2013 ↓, s. 32, cytat: „STM służy do tworzenia kodu bezpiecznego ze względu na watki i jest rozwiązaniem wyższego poziomu niż blokady z Javy. Zamiast stosować podatne na błędy strategie blokowania danych, można zabezpieczyć współużytkowany stan za pomocą transakcji. Jest to dużo lepsze podejście, ponieważ wielu programistów dobrze zna transakcje z uwagi na doświadczenie w korzystaniu z baz danych.”
- ↑ Bedra i Halloway 2013 ↓, s. 26, cytat: „Ponieważ w wersji w języku Clojure nie ma rozgałęzień, kod jest bardziej czytelny i łatwiejszy do przetestowania. Zalety te są jeszcze wyraźniejsze w większych programach. Ponadto, choć kod jest zwięzły, można go łatwo zrozumieć.”
Bibliografia
- Rich Hickey: Rationale. clojure.org. [dostęp 2016-03-19].
- Aaron Bedra, Stuart Halloway: Programowanie w języku Clojure. Tomasz Walczak (tłum.). Helion, 2013. ISBN 978-83-246-5372-0.
Linki zewnętrzne
- Oficjalna strona Clojure (ang.),
- Strona Clojure. clojure.com. [zarchiwizowane z tego adresu (2018-05-09)]. (ang.)
- Grupa Google (ang.),
- „Poczytaj mi Clojure” – podręcznik
- Obszerne wprowadzenie (ang.),
- Zbiór popularnych odsyłaczy dotyczących Clojure (ang.).
- REPL online - interaktywna konsola w przeglądarce (ang.).