Clojure

Clojure
Paradigmafunkcionální, multiparadigmový
Vznik2007
VývojářRich Hickey
První vydání2007
Poslední verze1.9.0 (8. prosince 2017[1])
Typová kontroladynamické, silné
Ovlivněn jazykyLisp, ML, Haskell, Erlang[2]
Ovlivnil jazykyElixir, Hy, Pixie, Rhine
OSMultiplatformní
LicenceEclipse Public License
Webclojure.org

Clojure (výslovnost [ˈkloužəːr]) je v informatice moderní dialekt programovacího jazyka Lisp. Jedná se o univerzální jazyk podporující funkcionální programování, který se zaměřuje na zjednodušení vývoje vícevláknových aplikací. Clojure používá běhové prostředí JVM nebo CLR, přičemž zastává filozofii kódu, který se chová jako data a implementuje sofistikovaný Lispový makrosystém.

Filozofie

Rich Hickey vyvinul Clojure, protože si přál moderní Lisp spolupracující s rozšířenou platformou Java, který by byl navržen pro vývoj vícevláknových aplikací.[3][4]

Clojure používá pro řízení souběžnosti koncept tzv. identit,[5] který si lze představit jako sérii v čase neměnitelných stavů. Jelikož tyto stavy mají neměnitelné hodnoty, může nad nimi paralelně operovat jakýkoliv počet vláken a řízení souběžnosti se stává otázkou spravování přechodů z jednoho stavu do dalšího. Pro tento účel Clojure poskytuje 4 měnitelné referenční typy, kde každý má jasně definovanou sémantiku pro přechod mezi stavy.

Syntaxe

Jako každý Lisp, syntaxe jazyka Clojure je postavena na s-výrazech, které jsou nejprve rozebrány do datových struktur před tím než jsou zkompilovány. Clojure podporuje literály pro struktury jako seznamy, mapy, množiny a pole, které jsou kompilátoru předány tak jak jsou. Clojure je Lisp-1 a není zamýšleno, aby byl kompatibilní s ostatními dialekty Lispu.

Makra

Makro je konstrukce, které v argumentech předáme S-výrazy, ze kterých je následně sestaven libovolný kód. Poté se tento kód vykoná. Systém maker v Clojuru je velice podobný kódu Common Lispu.

Vlastnosti jazyka

  • dynamický vývoj pomocí REPL
  • funkce jsou first-class objekty s důrazem na rekurzi namísto smyček vytvářejících postranní efekty
  • líně vyhodnocované sekvence
  • poskytuje bohatou sadu neměnitelných datových struktur
  • souběžné programování pomocí softwarové transakční paměti, agentový systém a dynamický typový systém
  • multimetody poskytují dynamické spuštění metod, jejichž konkrétní implementace je vybrána na základě typu předaných parametrů
  • jazyk je kompilovaný do JVM bajtkódu
  • silná integrace s Javou: kód jazyka Clojure kompilovaný do JVM bajtkódu může být snadno nasazený do běžného prostředí JVM a aplikačních serverů bez dalších potíží; jazyk dále poskytuje makra, která usnadňují použití existujících Java API; jeho struktury implementují standardní rozhraní Javy, což umožňuje spouštět kód napsaný v Clojure z Javy

Příklady

Ahoj světe

(println "Ahoj světe!")

GUI verze

(javax.swing.JOptionPane/showMessageDialog nil "Ahoj světe")

Vláknově bezpečný generátor unikátních sériových čísel

(let [i (atom 0)]
  (defn generate-unique-id
    "Vrací různá číselná ID pro každé volání."
    []
    (swap! i inc)))

Anonymní podtřída java.io.Writer

Tato třída nikam nezapisuje a obsahuje makro, které umlčí všechno vypisování.

(def bit-bucket-writer
  (proxy [java.io.Writer] []
    (write [buf] nil)
    (close []    nil)
    (flush []    nil)))

(defmacro noprint
  "Vykoná předané výrazy a umlčí všechna vypisování na *out* (standardní výstup)."
  [& forms]
  `(binding [*out* bit-bucket-writer]
     ~@forms))

(noprint
 (println "Zdravím nikoho!"))

Vlákna

Následující příklad ukazuje 10 vláken operujících nad společnou datovou strukturou, která se skládá ze 100 vektorů, každý obsahující 10 (zpočátku po sobě jdoucích) unikátních čísel. Každé vlákno vybírá 2 náhodné pozice ve 2 náhodných vektorech a prohazuje je. Všechny změny ve vektorech probíhají v transakcích s použitím softwarové transakční paměti, a proto ani po 100 000 iteracích každého vlákna se neztratí žádné číslo.

(defn run [nvecs nitems nthreads niters]
  (let [vec-refs (vec (map (comp ref vec)
                           (partition nitems (range (* nvecs nitems)))))
        swap #(let [v1 (rand-int nvecs)
                    v2 (rand-int nvecs)
                    i1 (rand-int nitems)
                    i2 (rand-int nitems)]
                (dosync
                 (let [temp (nth @(vec-refs v1) i1)]
                   (alter (vec-refs v1) assoc i1 (nth @(vec-refs v2) i2))
                   (alter (vec-refs v2) assoc i2 temp))))
        report #(do
                 (prn (map deref vec-refs))
                 (println "Distinct:"
                          (count (distinct (apply concat (map deref vec-refs))))))]
    (report)
    (dorun (apply pcalls (repeat nthreads #(dotimes [_ niters] (swap)))))
    (report)))

(run 100 10 10 100000)

Výstup

([0 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18 19] 
 [990 991 992 993 994 995 996 997 998 999])
Distinct: 1000
 
([382 318 466 963 619 22 21 273 45 596] [808 639 804 471 394 904 952 75 289 778] 
 [484 216 622 139 651 592 379 228 242 355])
Distinct: 1000

Reference

  1. Central Repository: org/clojure/clojure/1.9.0 [online]. Rev. 2017-12-08 [cit. 2018-02-23]. Dostupné online. (anglicky) [nedostupný zdroj]
  2. HICKEY, Rich. Books that influenced Clojure [online]. 2009-06-30 [cit. 2018-02-23]. Dostupné online. (anglicky) 
  3. Clojure - Rationale [online]. Rich Hickey, 2018-02-21 [cit. 2018-02-23]. Dostupné online. (anglicky) 
  4. Charles. Expert to Expert: Rich Hickey and Brian Beckman - Inside Clojure [online]. Microsoft, 2009-10-06 [cit. 2018-02-23]. (Channel 9. Going Deep). Dostupné online. (anglicky) 
  5. Clojure - Values and Change: Clojure‘s approach to Identity and State [online]. Rich Hickey, 2018-02-21 [cit. 2018-02-23]. Dostupné online. (anglicky) 

Literatura

Externí odkazy