Obsah
1. Novinky v Clojure verze 1.8.0
2. Instalace Clojure 1.8.0 bez použití nástroje Leiningen
3. Spuštění interaktivního REPLu
4. Instalace Clojure 1.8.0 s použitím nástroje Leiningen
5. Spuštění interaktivního REPLu
6. Rozšíření repertoáru funkcí ve jmenném prostoru clojure.string
9. Spuštění serveru a použití telnetu k přístupu k REPLu
11. Použití REPLu přístupného přes socket
12. Další vylepšení v Clojure 1.8.0
13. Odkazy na předchozí části tohoto seriálu
1. Novinky v Clojure verze 1.8.0
Před týdnem, konkrétně dne 19.1.2016, byla vydána nová verze programovacího jazyka Clojure. Jak jsme vás již informovali ve zprávičce, jedná se o verzi 1.8.0. Nutno říci, že tato verze vlastně není příliš přelomová a už vůbec ne revoluční, což může znamenat to, že se programovací jazyk Clojure dostává do stabilní fáze vývoje, kdy by radikální změny byly vnímány spíše negativně. V rámci Clojure 1.8.0 došlo k přidání pěti nových a užitečných funkcí do jmenného prostoru clojure.string, dále je možné se připojit k interaktivní smyčce REPL přes k tomu vytvořený socket (což je sice zdánlivě malá změna, která má však poměrně dalekosáhlé praktické důsledky) a taktéž byl optimalizován překlad zdrojových kódů napsaných v jazyce Clojure do bajtkódu JVM. Na tomto místě je ještě vhodné dodat, že před vydáním Clojure 1.8.0 byl do standardních knihoven dodán jmenný prostor clojure.async, což již JE poměrně závažné vylepšení, kterému se kvůli jeho důležitosti budeme věnovat v samostatném článku.
2. Instalace Clojure 1.8.0 bez použití nástroje Leiningen
Nejprve si ukažme, jakým způsobem je možné na vývojový počítač nainstalovat programovací jazyk Clojure verze 1.8.0 v případě, že z nějakého důvodu nechcete používat nástroj Leiningen. Pro naprostou většinu projektů je sice doporučováno Leiningen použít, ovšem mohou existovat situace, kdy to není možné. V těchto situacích postačuje stáhnout již připravený zip archiv obsahující jak samotný jazyk Clojure (překladač do bajtkódu, runtime i vlastní smyčku REPL), zdrojové kódy Clojure, tak i základní knihovny. Celý archiv je dostupný na adrese http://repo1.maven.org/maven2/org/clojure/clojure/1.8.0/clojure-1.8.0.zip, takže nejprve použijeme wget pro jeho stažení do lokálního adresáře:
wget http://repo1.maven.org/maven2/org/clojure/clojure/1.8.0/clojure-1.8.0.zip --2016-01-24 10:17:27-- http://repo1.maven.org/maven2/org/clojure/clojure/1.8.0/clojure-1.8.0.zip Resolving repo1.maven.org (repo1.maven.org)... 185.31.17.209 Connecting to repo1.maven.org (repo1.maven.org)|185.31.17.209|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 5017209 (4,8M) [application/zip] Saving to: "clojure-1.8.0.zip" 100%[=====================================================================================================>] 5 017 209 908KB/s in 5,9s 2016-01-24 10:17:33 (837 KB/s) - "clojure-1.8.0.zip" saved [5017209/5017209]
Dále je nutné archiv rozbali, což lze provést přímo v pracovním adresáři
unzip clojure-1.8.0.zip Archive: clojure-1.8.0.zip creating: clojure-1.8.0/ creating: clojure-1.8.0/src/ creating: clojure-1.8.0/src/script/ creating: clojure-1.8.0/src/jvm/ ... ... ... inflating: clojure-1.8.0/clojure-1.8.0-slim.jar inflating: clojure-1.8.0/clojure-1.8.0.jar inflating: clojure-1.8.0/pom.xml inflating: clojure-1.8.0/build.xml inflating: clojure-1.8.0/readme.txt inflating: clojure-1.8.0/changes.md inflating: clojure-1.8.0/clojure.iml inflating: clojure-1.8.0/epl-v10.html
Nejdůležitější je pro nás nyní především soubor nazvaný clojure-1.8.0/clojure-1.8.0.jar obsahující všechny součásti interpretru a překladače jazyka Clojure, včetně REPLu a základních knihoven.
Poznámka: pro běh Clojure (libovolné verze) je samozřejmě zapotřebí mít nainstalováno JRE (Java Runtime Environment), podobně jako pro spuštění dalších javovských aplikací. Postačuje jak verze 7, tak i novější verze 8. Já jsem v dnešním článku vše testoval na verzi 7 (konkrétně na OpenJDK 1.7.0_79, tj. build JRE má číslo 7u79), a to především z toho důvodu, že na produkčních systémech je tato verze pravděpodobně používána častěji, než JDK/JRE 8.
3. Spuštění interaktivního REPLu
Spuštění interaktivní smyčky REPL, v níž mnoho programátorů tráví při tvorbě aplikací nejvíce času, se provede velmi jednoduše:
cd clojure-1.8.0 java -jar clojure-1.8.0.jar Clojure 1.8.0 user=>
Ve skutečnosti má takto „primitivně“ spuštěný REPL několik nevýhod, a to především absenci historie příkazové řádky. Tento nedostatek nahradíme nástrojem nazvaným příhodně readline wrapper, který dokáže historii příkazů zachovat a kdykoli vyvolat klávesovými zkratkami známými například z BASHe. Pokud chcete readline wrapper při vývoji a testování s využitím REPL použít (což je v tomto případě pro praktické použití takřka nezbytné), nainstalujte si nejprve balíček nazvaný rlwrap a posléze spusťte REPL jazyka Clojure následujícím způsobem:
cd clojure-1.8.0 rlwrap java -jar clojure-1.8.0.jar Clojure 1.8.0 user=>
4. Instalace Clojure 1.8.0 s použitím nástroje Leiningen
Instalace Clojure verze 1.8.0 s využitím nástroje Leiningen je velmi jednoduchá. Nejprve vytvoříme nový projekt, a to příkazem:
lein new app clojure8-test Generating a project called clojure8-test based on the 'app' template.
Po zadání tohoto příkazu by se měl vytvořit adresář obsahující strukturu nového projektu:
. ├── doc │ └── intro.md ├── LICENSE ├── project.clj ├── README.md ├── resources ├── src │ └── clojure8_test │ └── core.clj └── test └── clojure8_test └── core_test.clj 6 directories, 6 files
Podívejme se nyní na obsah projektového souboru nazvaného project.clj. Ten může vypadat takto:
(defproject clojure8-test "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"]] :main ^:skip-aot clojure8-test.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Označenou část projektového souboru změníme takovým způsobem, aby se namísto verze 1.5.0, 1.6.0 či 1.7.0 používala verze 1.8.0:
(defproject clojure8-test "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"]] :main ^:skip-aot clojure8-test.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Následně stačí uložit novou verzi projektového souboru a na příkazové řádce zadat příkaz pro stažení všech knihoven a balíčků, na nichž projekt závisí:
lein deps Retrieving org/clojure/clojure/1.8.0/clojure-1.8.0.pom from central Retrieving org/clojure/clojure/1.8.0/clojure-1.8.0.jar from central
Z vypsaných zpráv je zřejmé, že skutečně došlo ke stažení nové verze jazyka Clojure. Standardně se interpretry Clojure ukládají do adresáře ~/.m2/repository/org/clojure/clojure, který může obsahovat i několik verzí interpretu. To je ve skutečnosti celkem běžné, protože mnoho knihoven má ve svém popisu (projektovém souboru) uvedenou právě nějakou starší verzi. Podívejme se, jak struktura výše zmíněného adresáře vypadá na počítači, který je aktivně používán pro vývoj v jazyce Clojure:
~/.m2/repository/org/clojure/clojure/ ├── 1.2.1 │ ├── clojure-1.2.1.jar │ ├── clojure-1.2.1.jar.sha1 │ ├── clojure-1.2.1.pom │ ├── clojure-1.2.1.pom.sha1 │ └── _maven.repositories ├── 1.3.0 │ ├── clojure-1.3.0.pom │ ├── clojure-1.3.0.pom.sha1 │ └── _maven.repositories ├── 1.4.0 │ ├── clojure-1.4.0.pom │ ├── clojure-1.4.0.pom.sha1 │ └── _maven.repositories ├── 1.5.1 │ ├── clojure-1.5.1.jar │ ├── clojure-1.5.1.jar.sha1 │ ├── clojure-1.5.1.pom │ ├── clojure-1.5.1.pom.sha1 │ └── _maven.repositories ├── 1.6.0 │ ├── clojure-1.6.0.jar │ ├── clojure-1.6.0.jar.sha1 │ ├── clojure-1.6.0.pom │ ├── clojure-1.6.0.pom.sha1 │ └── _maven.repositories ├── 1.7.0 │ ├── clojure-1.7.0.jar │ ├── clojure-1.7.0.jar.sha1 │ ├── clojure-1.7.0.pom │ ├── clojure-1.7.0.pom.sha1 │ └── _maven.repositories ├── 1.7.0-RC1 │ ├── clojure-1.7.0-RC1.pom │ ├── clojure-1.7.0-RC1.pom.sha1 │ └── _maven.repositories └── 1.8.0 ├── clojure-1.8.0.jar ├── clojure-1.8.0.jar.sha1 ├── clojure-1.8.0.pom ├── clojure-1.8.0.pom.sha1 └── _maven.repositories 8 directories, 34 files
V případě Clojure verze 1.8.0 vznikl při instalaci adresář s pěticí souborů, přičemž pro vývoj, ladění i spouštění programů se používá pouze Java archiv uvedený na prvním místě:
ls -l ~/.m2/repository/org/clojure/clojure/1.8.0 total 3564 -rw-r--r-- 1 tester tester 3622815 led 24 10:14 clojure-1.8.0.jar -rw-r--r-- 1 tester tester 40 led 24 10:14 clojure-1.8.0.jar.sha1 -rw-r--r-- 1 tester tester 8547 led 24 10:14 clojure-1.8.0.pom -rw-r--r-- 1 tester tester 40 led 24 10:14 clojure-1.8.0.pom.sha1 -rw-r--r-- 1 tester tester 180 led 24 10:14 _maven.repositories
Poznámka: samotný projekt je možné bez obav smazat, protože jeho jedinou úlohou bylo nainstalovat Clojure 1.8.0 do adresáře ~/.m2 a otestovat REPL (viz další kapitolu).
5. Spuštění interaktivního REPLu
Spuštění interaktivní smyčky REPL je v případě použití projektu používajícího nástroj Leiningen velmi snadné. Postačuje pouze v adresáři s projektem zadat příkaz lein repl:
lein repl nREPL server started on port 47224 on host 127.0.0.1 - nrepl://127.0.0.1:47224 REPL-y 0.3.5, nREPL 0.2.6 Clojure 1.8.0 OpenJDK 64-Bit Server VM 1.7.0_79-b14 Docs: (doc function-name-here) (find-doc "part-of-name-here") Source: (source function-name-here) Javadoc: (javadoc java-object-or-class-here) Exit: Control+D or (exit) or (quit) Results: Stored in vars *1, *2, *3, an exception in *e clojure8-test.core=>
Tato forma smyčky REPL programátorům nabízí mnohem více možností, než „klasická“ minimalisticky pojatá smyčka REPL, která je součástí interpretru Clojure. K dispozici je historie příkazů, lze přistupovat ke speciálním symbolům *1, *e atd. Právě tuto smyčku použijeme v dalším textu při vysvětlování nových možností Clojure 1.8.0.
6. Rozšíření repertoáru funkcí ve jmenném prostoru clojure.string
Do jmenného prostoru clojure.string bylo přidáno pět nových funkcí, které se používají pro test, zda nějaký řetězec obsahuje zadaný podřetězec a popř. na jaké pozici se tento podřetězec nachází. První tři funkce vrací hodnotu true či false, proto se jedná o takzvané „predikáty“, jejichž jména podle ustanovených jmenných konvencí končí znakem otazník. Další dvě funkce vrací index nalezeného podřetězce popř. hodnotu nil, pokud se nalezení nepodařilo. Podívejme se na tabulku s novými funkcemi:
# | Funkce | Stručný popis |
---|---|---|
1 | starts-with? | test, zda řetězec začíná zadaným podřetězcem |
2 | ends-with? | test, zda řetězec končí zadaným podřetězcem |
2 | includes? | test, zda řetězec obsahuje zadaný podřetězec |
3 | index-of | vrátí první výskyt znaku v řetězci popř. nil |
4 | last-index-of | vrátí poslední výskyt znaku v řetězci popř. nil |
Tyto funkce byly přidány primárně z toho důvodu, aby byly dostupné i v ClojureScriptu. Programátoři používající předchozí verzi jazyka Clojure se museli uchýlit k použití metod třídy java.lang.String. Skutečně, nové funkce jsou částečně s těmito metodami shodné:
# | Funkce | Odpovídající metoda třídy java.lang.String |
---|---|---|
1 | starts-with? | .startsWith |
2 | ends-with? | .endsWith |
2 | includes? | .contains |
3 | index-of | .indexOf |
4 | last-index-of | .lastIndexOf |
Ve skutečnosti však existuje několik rozdílů mezi novými funkcemi a odpovídajícími javovskými metodami. Především funkce lze zavolat i v tom případě, kdy jejich prvním parametrem není řetězec ale například číslo či objekt. Nejprve je tato reference automaticky převedena na řetězec a posléze je funkce zavolána, což v případě metod pochopitelně není možné (přesněji řečeno v Javě jakožto OO jazyku založeném na třídách to není možné). Druhý rozdíl je v praxi důležitější: funkce index-of a last-index-of v případě, že podřetězec nebyl nalezen, vrací speciální hodnotu nil, zatímco metody String.indexOf a String.lastIndexOf vrací ve stejném případě hodnotu –1 (za to můžeme „vděčit“ rigidnímu typovému systému Javy a taktéž striktnímu rozlišování mezi primitivními typy a referenčními typy). Ostatně, hodnota nil je praktičtější, protože ji lze použít přímo v rozhodovacích konstrukcích, kde má stejný význam jako pravdivostní hodnota false.
7. Demonstrační příklady
Vyzkoušejme si nyní výše uvedenou pětici funkcí na demonstračních příkladech zadávaných přímo do interaktivní smyčky REPL. Nejdříve REPL spustíme:
lein repl nREPL server started on port 51457 on host 127.0.0.1 - nrepl://127.0.0.1:51457 REPL-y 0.3.5, nREPL 0.2.6 Clojure 1.8.0 OpenJDK 64-Bit Server VM 1.7.0_79-b14 Docs: (doc function-name-here) (find-doc "part-of-name-here") Source: (source function-name-here) Javadoc: (javadoc java-object-or-class-here) Exit: Control+D or (exit) or (quit) Results: Stored in vars *1, *2, *3, an exception in *e
Nyní načteme všechny funkce, makra a symboly definované ve jmenném prostoru clojure.string, přičemž namísto nutnosti zadávání plného jména tohoto prostoru si zvolíme pouze kratší alias str (vůbec přitom nevadí, že dojde ke „kolizi“ s funkcí str, protože jméno modulu a jméno funkce se vždy bude uvádět v jiném kontextu):
clojure8-test.core=> (require '[clojure.string :as str]) nil
Navážeme symbol s na řetězec „Hello world!“:
clojure8-test.core=> (def s "Hello world!") #'clojure8-test.core/s
Konečně se můžeme pustit do testování nových řetězcových funkcí:
; nalezení prvního výskytu znaku "o" clojure8-test.core=> (str/index-of s "o") 4 ; nalezení prvního výskytu podřetězce "wo" clojure8-test.core=> (str/index-of s "wo") 6 ; pokud se podřetězec nenalezne, vrací se hodnota nil, nikoli -1: clojure8-test.core=> (str/index-of s "xxx") nil ; hledání výskytu znaku od určité pozice clojure8-test.core=> (str/index-of s "o" 4) 4 ; hledání výskytu znaku od určité pozice clojure8-test.core=> (str/index-of s "o" 5) 7 ; pokud se podřetězec nenalezne, vrací se hodnota nil, nikoli -1: clojure8-test.core=> (str/index-of s "o" 10) nil ; hledání posledního výskytu znaku clojure8-test.core=> (str/last-index-of s "o") 7 ; hledání posledního výskytu podřetězce clojure8-test.core=> (str/last-index-of s "wo") 6 ; hledání posledního výskytu podřetězce, opět se může vracet nil clojure8-test.core=> (str/last-index-of s "foo") nil ; tato funkce vrací true či false v závislosti na tom, zda je nalezen podřetězec clojure8-test.core=> (str/includes? s "wor") true ; tato funkce vrací true či false v závislosti na tom, zda je nalezen podřetězec clojure8-test.core=> (str/includes? s "xyzzy") false ; tato funkce vrací true či false v závislosti na tom, zda je na začátku nalezen podřetězec clojure8-test.core=> (str/starts-with? s "H") true ; tato funkce vrací true či false v závislosti na tom, zda je na začátku nalezen podřetězec clojure8-test.core=> (str/starts-with? s "x") false ; tato funkce vrací true či false v závislosti na tom, zda je na začátku nalezen podřetězec clojure8-test.core=> (str/starts-with? s "Hello") true ; tato funkce vrací true či false v závislosti na tom, zda je na konci nalezen podřetězec clojure8-test.core=> (str/ends-with? s "!") true ; tato funkce vrací true či false v závislosti na tom, zda je na konci nalezen podřetězec clojure8-test.core=> (str/ends-with? s "x") false ; tato funkce vrací true či false v závislosti na tom, zda je na konci nalezen podřetězec clojure8-test.core=> (str/ends-with? s "world!") true
Některé specialitky:
; velmi častá chyba při použití funkce contains?, kterou nelze na řetězce použít ; nová funkce includes? doufejme nesprávné použití contains? omezí ; (mnoho programátorů si myslí, že contains? je nejhůře pojmenovanou funkcí v Clojure vůbec :-) clojure8-test.core=> (contains? s "o") ; numerická hodnota je převedena na řetězec, v němž se pak hledá znak clojure8-test.core=> (str/includes? 1234 "3") true ; výsledek funkce je převeden na řetězec, v němž se pak hledá znak clojure8-test.core=> (str/includes? (* 6 7) "4") true
Pokud vám z nějakého důvodu nevyhovuje nutnost specifikace jmenného prostoru clojure.string či jeho aliasu str, je možné provést i následující operaci, která všechny symboly ze jmenného prostoru clojure.string umístí do aktivního jmenného prostoru (se všemi důsledky, ostatně se podívejte na překrytí některých jmen):
clojure8-test.core=> (require '[clojure.string :refer :all]) WARNING: reverse already refers to: #'clojure.core/reverse in namespace: clojure8-test.core, being replaced by: #'clojure.string/reverse WARNING: replace already refers to: #'clojure.core/replace in namespace: clojure8-test.core, being replaced by: #'clojure.string/replace nil
Nyní je již možné funkce volat bez přidání aliasu na začátek:
clojure8-test.core=> (includes? s "world") true clojure8-test.core=> (starts-with? s "H") true clojure8-test.core=> (starts-with? s "x") false clojure8-test.core=> (ends-with? s "!") true
8. Socket server
Poměrně důležitou a především pak praktickou novinkou ve verzi 1.8.0 je zahrnutí jednoduchého a na systémové prostředky nenáročného socket serveru, který může být při startu aplikace spuštěn a na určeném portu (či portech) může čekat na vzdálené připojení, typicky k interaktivní smyčce REPL. Díky této nové vlastnosti je například možné se prakticky kdykoli připojit k již běžící aplikaci, provést ladění, zjištění aktuálního vytížení aplikace, aplikovat změnu programového kódu některé funkce či změnu hodnoty proměnné (například atomu), a to bez nutnosti restartu aplikace a navíc bez nutnosti nějakým způsobem přistupovat ke standardnímu vstupu, výstupu a chybovému výstupu, který je ke smyčce REPL přiřazen. V následující kapitole si ukážeme typické použití serveru.
9. Spuštění serveru a použití telnetu k přístupu k REPLu
To, zda se server spustí či nikoli, je ovlivněno existencí vlastnosti nazvané clojure.server.{jméno-serveru}, kde se do poslední části jména vlastnosti musí zadat jednoznačný identifikátor. Díky tomu, že se do jména vlastnosti zadává i uživatelsky volitelná část, je možné spustit dokonce i větší množství serverů, které se budou lišit jak svými porty (na nichž čekají na požadavky), tak i svými jmény (či dalšími vlastnostmi). Jméno vlastnosti tedy může vypadat takto:
clojure.server.repl1
Hodnotou vlastnosti je řetězec obsahující mapu (ve smyslu jazyka Clojure), která může obsahovat tyto klíče:
# | Klíč | Vyžadováno? | Výchozí hodnota | Význam |
---|---|---|---|---|
1 | :address | ne | × | IP adresa nebo hostname |
2 | :port | ano | × | port, na němž server bude čekat na požadavky |
3 | :accept | ano | × | která funkce se použije pro příjem požadavků, typicky clojure.core.server/repl |
4 | :args | ne | () | další argumenty předávané funkci specifikované v :accept |
5 | :server-daemon | ne | true | pokud je nastaveno na true (výchozí hodnota), nebude vlákno serveru bránit ukončení aplikace |
6 | :client-deamon | ne | true | dtto pro klienta (pro REPL nevýznamné) |
7 | :bind-err | ne | true | pokud je nastaveno na true (výchozí hodnota), bude se i chybový výstup posílat klientovi |
Příklad specifikace vlastnosti nazvané clojure.server.repl při spouštění JVM:
-Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}"
Spuštění JVM s interpretrem jazyka Clojure může vypadat takto:
java -Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}" -jar clojure-1.8.0.jar

Obrázek 1: V horním terminálu je spuštěn interpret Clojure i se serverem. V dolním terminálu se přes telnet připojujeme k serveru a získáme tak vlastní smyčku REPL se samostatným nastavením, ovšem s přístupem ke všem symbolům,které jsou v interpretru dostupné. Nové symboly zde lze i vytvářet a ovlivňovat tak běžící aplikaci.
Dokonce je možné si spustit dva či více serverů, například:
java -Dclojure.server.repl1="{:port 5555 :accept clojure.core.server/repl}" -Dclojure.server.repl2="{:port 5556 :accept clojure.core.server/repl}" -jar clojure-1.8.0.jar
Každý server samozřejmě musí používat jiný port, na němž čeká na požadavky od klientů.

Obrázek 2: Zde došlo ke spuštění dvou serverů, k nimž jsem se ihned po jejich vytvoření připojil.

Obrázek 3: Po skončení aplikace jsou klienti násilně odpojeni, protože jsme nikde nespecifikovali, že má server běžet v režimu démona.
10. *out*, *err*, clojure.core.server/*session* a další symboly, které mají v serveru odlišné nastavení
Jak jsme si již řekli v předchozí kapitole, je většina symbolů (ve všech jmenných prostorech) pro hlavní část aplikace i pro vlákno, v němž je implementován server, shodné, lze k nim přistupovat, měnit je atd. Existuje však několik objektů, které musí mít odlišnou hodnotu. Jedná se samozřejmě o vstupní a výstupní proudy reprezentované symboly *in*, *out* a *err*. Pokud se uživatel připojí k aplikaci přes socket (na kterém poslouchá server), samozřejmě očekává, že tyto symboly budou nastaveny takovým způsobem, že vstup i výstup bude prováděn přes socket a ne přes standardní vstup a výstup navázaný na terminál, v němž byla aplikace spuštěna. Dalším speciálním symbolem je clojure.core.server/*session*, na nějž je navázána mapa obsahující například tyto hodnoty:
{:server "repl", :client "1"}
Vidíme zde jméno serveru, tj. poslední část jména příslušné vlastnosti) a identifikaci klienta. Pro hlavní smyčku REPL tento symbol neexistuje.
11. Použití REPLu přístupného přes socket
Podívejme se nyní na dosti umělý demonstrační příklad, na němž si ukážeme použití smyčky REPL. V tomto příkladu se v nekonečné smyčce postupně (konkrétně v sekundových intervalech) zvyšuje hodnota atomu o jedničku. Celý příklad může vypadat takto:
(def counter (atom 0)) (doseq [i (range)] (reset! counter i) (Thread/sleep 1000))
Nejprve spustíme interpret jazyka Clojure:
java -Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}" -jar clojure-1.8.0.jar
Načteme a spustíme výše uvedený příklad, který jsme si předtím uložili do souboru nazvaného test.clj:
(load-file "test.clj")
Nyní se hlavní smyčka REPL „odmlčí“, protože vyhodnocuje nekonečnou sekvenci a v sekundových intervalech nastavuje atom nazvaný counter na hodnotu, kterou má aktuální prvek této sekvence.
V novém terminálu se k aplikaci přihlásíme přes server očekávající požadavky na portu číslo 5555:
telnet localhost 5555 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'.
A ihned si můžeme vypsat aktuální hodnotu uloženou do atomu counter:
user=> @counter 16 user=> @counter 21
Po násilném ukončení aplikace (Ctrl+C) se ukončí i sezení spuštěné přes Telnet:
user=> Connection closed by foreign host.
12. Další vylepšení v Clojure 1.8.0
Další zajímavé vylepšení jazyka Clojure bylo vyřešeno v rámci CLJ-1263. Jedná se o interní optimalizaci využívanou při volání funkcí, kdy se namísto relativně složité dereference, načtení „univerzálního“ rozhraní IFn a zavolání instrukce invokeinterface používá jediná instrukce invokevirtual, což je rychlejší. Typicky se tato optimalizace využívá pro funkce označené tagem :^static, ideálně ještě s určením datových typů všech parametrů funkce i její návratové hodnoty – v tomto případě je funkce přeložena prakticky stejným způsobem, jako plně typovaná Javovská metoda.
13. Odkazy na předchozí části tohoto seriálu
- Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/ - Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (2)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/ - Programovací jazyk Clojure – triky při práci s řetězci
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/ - Programovací jazyk Clojure – triky při práci s kolekcemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/ - Programovací jazyk Clojure – práce s mapami a množinami
http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/ - Programovací jazyk Clojure – základy zpracování XML
http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/ - Programovací jazyk Clojure – testování s využitím knihovny Expectations
http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/ - Programovací jazyk Clojure – některé užitečné triky použitelné (nejenom) v testech
http://www.root.cz/clanky/programovaci-jazyk-clojure-nektere-uzitecne-triky-pouzitelne-nejenom-v-testech/ - Enlive – výkonný šablonovací systém pro jazyk Clojure
http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/ - Nástroj Leiningen a programovací jazyk Clojure: tvorba vlastních knihoven pro veřejný repositář Clojars
http://www.root.cz/clanky/nastroj-leiningen-a-programovaci-jazyk-clojure-tvorba-vlastnich-knihoven-pro-verejny-repositar-clojars/
14. Odkazy na Internetu
- Zip archiv s Clojure 1.8.0
http://repo1.maven.org/maven2/org/clojure/clojure/1.8.0/clojure-1.8.0.zip - Clojure 1.8 is now available
http://clojure.org/news/2016/01/19/clojure18 - Changes to Clojure in Version 1.8
https://github.com/clojure/clojure/blob/master/changes.md - Socket Server REPL
http://dev.clojure.org/display/design/Socket+Server+REPL - CLJ-1671: Clojure socket server
http://dev.clojure.org/jira/browse/CLJ-1671 - CLJ-1449: Add clojure.string functions for portability to ClojureScript
http://dev.clojure.org/jira/browse/CLJ-1449 - Launching a Socket Server
http://clojure.org/reference/repl_and_main#_launching_a_socket_server - API for clojure.string
http://clojure.github.io/clojure/branch-master/clojure.string-api.html - Clojars:
https://clojars.org/ - Seznam knihoven na Clojars:
https://clojars.org/projects - Clojure Cookbook: Templating HTML with Enlive
https://github.com/clojure-cookbook/clojure-cookbook/blob/master/07_webapps/7–11_enlive.asciidoc - An Introduction to Enlive
https://github.com/swannodette/enlive-tutorial/ - Enlive na GitHubu
https://github.com/cgrand/enlive - Expectations: příklady atd.
http://jayfields.com/expectations/ - Expectations na GitHubu
https://github.com/jaycfields/expectations - Lein-expectations na GitHubu
https://github.com/gar3thjon3s/lein-expectations - Testing Clojure With Expectations
https://semaphoreci.com/blog/2014/09/23/testing-clojure-with-expectations.html - Clojure testing TDD/BDD libraries: clojure.test vs Midje vs Expectations vs Speclj
https://www.reddit.com/r/Clojure/comments/1viilt/clojure_testing_tddbdd_libraries_clojuretest_vs/ - Testing: One assertion per test
http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html - Rewriting Your Test Suite in Clojure in 24 hours
http://blog.circleci.com/rewriting-your-test-suite-in-clojure-in-24-hours/ - Clojure doc: zipper
http://clojuredocs.org/clojure.zip/zipper - Clojure doc: parse
http://clojuredocs.org/clojure.xml/parse - Clojure doc: xml-zip
http://clojuredocs.org/clojure.zip/xml-zip - Clojure doc: xml-seq
http://clojuredocs.org/clojure.core/xml-seq - Parsing XML in Clojure
https://github.com/clojuredocs/guides - Clojure Zipper Over Nested Vector
https://vitalyper.wordpress.com/2010/11/23/clojure-zipper-over-nested-vector/ - Understanding Clojure's PersistentVector implementation
http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation - Understanding Clojure's PersistentHashMap (deftwice…)
http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html - Assoc and Clojure's PersistentHashMap: part ii
http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html - Ideal Hashtrees (paper)
http://lampwww.epfl.ch/papers/idealhashtrees.pdf - Clojure home page
http://clojure.org/ - Clojure (downloads)
http://clojure.org/downloads - Clojure Sequences
http://clojure.org/sequences - Clojure Data Structures
http://clojure.org/data_structures - The Structure and Interpretation of Computer Programs: 2.2.1 Representing Sequences
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html#%_sec2.2.1 - The Structure and Interpretation of Computer Programs: 3.3.1 Mutable List Structure
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-22.html#%_sec3.3.1 - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc (rozcestník s dokumentací jazyka Clojure)
http://clojuredocs.org/ - Clojure (na Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (na Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - SICP (The Structure and Interpretation of Computer Programs)
http://mitpress.mit.edu/sicp/ - Pure function
http://en.wikipedia.org/wiki/Pure_function - Funkcionální programování
http://cs.wikipedia.org/wiki/Funkcionální_programování - Čistě funkcionální (datové struktury, jazyky, programování)
http://cs.wikipedia.org/wiki/Čistě_funkcionální - Clojure Macro Tutorial (Part I, Getting the Compiler to Write Your Code For You)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-i-getting.html - Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html - Clojure Macro Tutorial (Part III: Syntax Quote)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html - Tech behind Tech: Clojure Macros Simplified
http://techbehindtech.com/2010/09/28/clojure-macros-simplified/ - Fatvat – Exploring functional programming: Clojure Macros
http://www.fatvat.co.uk/2009/02/clojure-macros.html - Eulerovo číslo
http://cs.wikipedia.org/wiki/Eulerovo_číslo - List comprehension
http://en.wikipedia.org/wiki/List_comprehension - List Comprehensions in Clojure
http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html - Clojure Programming Concepts: List Comprehension
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#List_Comprehension - Clojure core API: for macro
http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/for - cirrus machina – The Clojure for macro
http://www.cirrusmachina.com/blog/comment/the-clojure-for-macro/ - Riastradh's Lisp Style Rules
http://mumble.net/~campbell/scheme/style.txt - Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Java Virtual Machine Support for Non-Java Languages
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html - Třída java.lang.String
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html - Třída java.lang.StringBuffer
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html - Třída java.lang.StringBuilder
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html - StringBuffer versus String
http://www.javaworld.com/article/2076072/build-ci-sdlc/stringbuffer-versus-string.html - Threading macro (dokumentace k jazyku Clojure)
https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/-> - Understanding the Clojure → macro
http://blog.fogus.me/2009/09/04/understanding-the-clojure-macro/ - clojure.inspector
http://clojure.github.io/clojure/clojure.inspector-api.html - The Clojure Toolbox
http://www.clojure-toolbox.com/ - Unit Testing in Clojure
http://nakkaya.com/2009/11/18/unit-testing-in-clojure/ - Testing in Clojure (Part-1: Unit testing)
http://blog.knoldus.com/2014/03/22/testing-in-clojure-part-1-unit-testing/ - API for clojure.test – Clojure v1.6 (stable)
https://clojure.github.io/clojure/clojure.test-api.html - Leiningen: úvodní stránka
http://leiningen.org/ - Leiningen: Git repository
https://github.com/technomancy/leiningen - leiningen-win-installer
http://leiningen-win-installer.djpowell.net/ - Clojure.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - Transient Data Structureshttp://clojure.org/transients