Novinky v Clojure verze 1.8.0

Pavel Tišnovský 26. 1. 2016

Jak jsme vás již informovali ve zprávičce, vyšla minulý týden nová verze programovacího jazyka Clojure. Některé změny se týkají základních knihoven, další pak optimalizací pro dosažení vyššího výkonu při překladu zdrojových kódů do bajtkódu JVM. Právě těmito změnami se budeme zabývat v dnešním článku.

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

7. Demonstrační příklady

8. Socket server

9. Spuštění serveru a použití telnetu k přístupu k REPLu

10. *out*, *err*, clojure.core.server/*session* a další symboly, které mají v serveru odlišné nastavení

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

14. Odkazy na Internetu

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/ma­ven2/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:

widgety

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

  1. Clojure 1: Úvod
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/
  2. Clojure 2: Symboly, kolekce atd.
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/
  3. 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/
  4. 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/
  5. 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/
  6. Clojure 6: Podpora pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/
  7. Clojure 7: Další funkce pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/
  8. 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/
  9. 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/
  10. Clojure 10: Kooperace mezi Clojure a Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/
  11. Clojure 11: Generátorová notace seznamu/list comprehension
    http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/
  12. 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/
  13. 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/
  14. Clojure 14: Základy práce se systémem maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/
  15. Clojure 15: Tvorba uživatelských maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/
  16. Clojure 16: Složitější uživatelská makra
    http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/
  17. Clojure 17: Využití standardních maker v praxi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/
  18. Clojure 18: Základní techniky optimalizace aplikací
    http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/
  19. Clojure 19: Vývojová prostředí pro Clojure
    http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/
  20. 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/
  21. Clojure 21: ClojureScript aneb překlad Clojure do JS
    http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/
  22. Leiningen: nástroj pro správu projektů napsaných v Clojure
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/
  23. 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/
  24. 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/
  25. 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/
  26. 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/
  27. 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/
  28. Programovací jazyk Clojure a databáze (1.část)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/
  29. Pluginy pro Leiningen
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/
  30. 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/
  31. 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/
  32. 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/
  33. 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/
  34. 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/
  35. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/
  36. 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/
  37. 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/
  38. Programovací jazyk Clojure a práce s Gitem
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/
  39. Programovací jazyk Clojure a práce s Gitem (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/
  40. Programovací jazyk Clojure – triky při práci s řetězci
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/
  41. Programovací jazyk Clojure – triky při práci s kolekcemi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/
  42. Programovací jazyk Clojure – práce s mapami a množinami
    http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/
  43. Programovací jazyk Clojure – základy zpracování XML
    http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/
  44. Programovací jazyk Clojure – testování s využitím knihovny Expectations
    http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/
  45. 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/
  46. Enlive – výkonný šablonovací systém pro jazyk Clojure
    http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/
  47. 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

  1. Zip archiv s Clojure 1.8.0
    http://repo1.maven.org/ma­ven2/org/clojure/clojure/1­.8.0/clojure-1.8.0.zip
  2. Clojure 1.8 is now available
    http://clojure.org/news/2016/01/19/clo­jure18
  3. Changes to Clojure in Version 1.8
    https://github.com/clojure/clo­jure/blob/master/changes.md
  4. Socket Server REPL
    http://dev.clojure.org/dis­play/design/Socket+Server+REPL
  5. CLJ-1671: Clojure socket server
    http://dev.clojure.org/jira/browse/CLJ-1671
  6. CLJ-1449: Add clojure.string functions for portability to ClojureScript
    http://dev.clojure.org/jira/browse/CLJ-1449
  7. Launching a Socket Server
    http://clojure.org/referen­ce/repl_and_main#_launchin­g_a_socket_server
  8. API for clojure.string
    http://clojure.github.io/clo­jure/branch-master/clojure.string-api.html
  9. Clojars:
    https://clojars.org/
  10. Seznam knihoven na Clojars:
    https://clojars.org/projects
  11. Clojure Cookbook: Templating HTML with Enlive
    https://github.com/clojure-cookbook/clojure-cookbook/blob/master/07_webapps/7–11_enlive.asciidoc
  12. An Introduction to Enlive
    https://github.com/swannodette/enlive-tutorial/
  13. Enlive na GitHubu
    https://github.com/cgrand/enlive
  14. Expectations: příklady atd.
    http://jayfields.com/expectations/
  15. Expectations na GitHubu
    https://github.com/jaycfi­elds/expectations
  16. Lein-expectations na GitHubu
    https://github.com/gar3thjon3s/lein-expectations
  17. Testing Clojure With Expectations
    https://semaphoreci.com/blog/2014/09/23/tes­ting-clojure-with-expectations.html
  18. Clojure testing TDD/BDD libraries: clojure.test vs Midje vs Expectations vs Speclj
    https://www.reddit.com/r/Clo­jure/comments/1viilt/cloju­re_testing_tddbdd_librari­es_clojuretest_vs/
  19. Testing: One assertion per test
    http://blog.jayfields.com/2007/06/tes­ting-one-assertion-per-test.html
  20. Rewriting Your Test Suite in Clojure in 24 hours
    http://blog.circleci.com/rewriting-your-test-suite-in-clojure-in-24-hours/
  21. Clojure doc: zipper
    http://clojuredocs.org/clo­jure.zip/zipper
  22. Clojure doc: parse
    http://clojuredocs.org/clo­jure.xml/parse
  23. Clojure doc: xml-zip
    http://clojuredocs.org/clojure.zip/xml-zip
  24. Clojure doc: xml-seq
    http://clojuredocs.org/clo­jure.core/xml-seq
  25. Parsing XML in Clojure
    https://github.com/clojuredocs/guides
  26. Clojure Zipper Over Nested Vector
    https://vitalyper.wordpres­s.com/2010/11/23/clojure-zipper-over-nested-vector/
  27. Understanding Clojure's PersistentVector implementation
    http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation
  28. Understanding Clojure's PersistentHashMap (deftwice…)
    http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html
  29. Assoc and Clojure's PersistentHashMap: part ii
    http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html
  30. Ideal Hashtrees (paper)
    http://lampwww.epfl.ch/pa­pers/idealhashtrees.pdf
  31. Clojure home page
    http://clojure.org/
  32. Clojure (downloads)
    http://clojure.org/downloads
  33. Clojure Sequences
    http://clojure.org/sequences
  34. Clojure Data Structures
    http://clojure.org/data_structures
  35. 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
  36. 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
  37. Clojure – Functional Programming for the JVM
    http://java.ociweb.com/mar­k/clojure/article.html
  38. Clojure quick reference
    http://faustus.webatu.com/clj-quick-ref.html
  39. 4Clojure
    http://www.4clojure.com/
  40. ClojureDoc (rozcestník s dokumentací jazyka Clojure)
    http://clojuredocs.org/
  41. Clojure (na Wikipedia EN)
    http://en.wikipedia.org/wiki/Clojure
  42. Clojure (na Wikipedia CS)
    http://cs.wikipedia.org/wiki/Clojure
  43. SICP (The Structure and Interpretation of Computer Programs)
    http://mitpress.mit.edu/sicp/
  44. Pure function
    http://en.wikipedia.org/wi­ki/Pure_function
  45. Funkcionální programování
    http://cs.wikipedia.org/wi­ki/Funkcionální_programová­ní
  46. Čistě funkcionální (datové struktury, jazyky, programování)
    http://cs.wikipedia.org/wi­ki/Čistě_funkcionální
  47. 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
  48. Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html
  49. Clojure Macro Tutorial (Part III: Syntax Quote)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html
  50. Tech behind Tech: Clojure Macros Simplified
    http://techbehindtech.com/2010/09/28/clo­jure-macros-simplified/
  51. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  52. Eulerovo číslo
    http://cs.wikipedia.org/wi­ki/Eulerovo_číslo
  53. List comprehension
    http://en.wikipedia.org/wi­ki/List_comprehension
  54. List Comprehensions in Clojure
    http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html
  55. Clojure Programming Concepts: List Comprehension
    http://en.wikibooks.org/wi­ki/Clojure_Programming/Con­cepts#List_Comprehension
  56. Clojure core API: for macro
    http://clojure.github.com/clo­jure/clojure.core-api.html#clojure.core/for
  57. cirrus machina – The Clojure for macro
    http://www.cirrusmachina.com/blog/com­ment/the-clojure-for-macro/
  58. Riastradh's Lisp Style Rules
    http://mumble.net/~campbe­ll/scheme/style.txt
  59. Dynamic Languages Strike Back
    http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html
  60. Scripting: Higher Level Programming for the 21st Century
    http://www.tcl.tk/doc/scripting.html
  61. Java Virtual Machine Support for Non-Java Languages
    http://docs.oracle.com/ja­vase/7/docs/technotes/gui­des/vm/multiple-language-support.html
  62. Třída java.lang.String
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­g.html
  63. Třída java.lang.StringBuffer
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­gBuffer.html
  64. Třída java.lang.StringBuilder
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­gBuilder.html
  65. StringBuffer versus String
    http://www.javaworld.com/ar­ticle/2076072/build-ci-sdlc/stringbuffer-versus-string.html
  66. Threading macro (dokumentace k jazyku Clojure)
    https://clojure.github.io/clo­jure/clojure.core-api.html#clojure.core/->
  67. Understanding the Clojure → macro
    http://blog.fogus.me/2009/09/04/un­derstanding-the-clojure-macro/
  68. clojure.inspector
    http://clojure.github.io/clo­jure/clojure.inspector-api.html
  69. The Clojure Toolbox
    http://www.clojure-toolbox.com/
  70. Unit Testing in Clojure
    http://nakkaya.com/2009/11/18/unit-testing-in-clojure/
  71. Testing in Clojure (Part-1: Unit testing)
    http://blog.knoldus.com/2014/03/22/tes­ting-in-clojure-part-1-unit-testing/
  72. API for clojure.test – Clojure v1.6 (stable)
    https://clojure.github.io/clo­jure/clojure.test-api.html
  73. Leiningen: úvodní stránka
    http://leiningen.org/
  74. Leiningen: Git repository
    https://github.com/techno­mancy/leiningen
  75. leiningen-win-installer
    http://leiningen-win-installer.djpowell.net/
  76. Clojure.org: Vars and the Global Environment
    http://clojure.org/Vars
  77. Clojure.org: Refs and Transactions
    http://clojure.org/Refs
  78. Clojure.org: Atoms
    http://clojure.org/Atoms
  79. Clojure.org: Agents as Asynchronous Actions
    http://clojure.org/agents
  80. Transient Data Structureshttp://clojure.or­g/transients
Našli jste v článku chybu?
Lupa.cz: Kde leží hardwarový pupek světa?

Kde leží hardwarový pupek světa?

Podnikatel.cz: „Lex Babiš“ Babišovi paradoxně pomůže

„Lex Babiš“ Babišovi paradoxně pomůže

120na80.cz: Co je padesátkrát sladší než cukr?

Co je padesátkrát sladší než cukr?

120na80.cz: Galerie: Čínští policisté testují českou minerálku

Galerie: Čínští policisté testují českou minerálku

Podnikatel.cz: Instalatér, malíř a elektrikář. "Vymřou"?

Instalatér, malíř a elektrikář. "Vymřou"?

Lupa.cz: Cimrman má hry na YouTube i vlastní doodle

Cimrman má hry na YouTube i vlastní doodle

DigiZone.cz: Ginx TV: pořad o počítačových hráčích

Ginx TV: pořad o počítačových hráčích

DigiZone.cz: Mordparta: trochu podchlazený 87. revír

Mordparta: trochu podchlazený 87. revír

DigiZone.cz: Nova opět stahuje „milionáře“

Nova opět stahuje „milionáře“

DigiZone.cz: Digi Slovakia zařazuje stanice SPI

Digi Slovakia zařazuje stanice SPI

Podnikatel.cz: Tyto pojmy k #EET byste měli znát

Tyto pojmy k #EET byste měli znát

Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

Byla finanční manažerka, teď cvičí jógu

Podnikatel.cz: Letáky? Lidi zuří, ale ony stále fungují

Letáky? Lidi zuří, ale ony stále fungují

Vitalia.cz: Antibakteriální mýdla nepomáhají, spíš škodí

Antibakteriální mýdla nepomáhají, spíš škodí

Vitalia.cz: dTest odhalil ten nejlepší kečup

dTest odhalil ten nejlepší kečup

Lupa.cz: Patička e-mailu závazná jako vlastnoruční podpis?

Patička e-mailu závazná jako vlastnoruční podpis?

DigiZone.cz: Světový pohár v přímém přenosu na ČT

Světový pohár v přímém přenosu na ČT

Vitalia.cz: Tradiční čínská medicína a rakovina

Tradiční čínská medicína a rakovina

DigiZone.cz: DVB-T2 ověřeno: seznam TV zveřejněn

DVB-T2 ověřeno: seznam TV zveřejněn

Lupa.cz: Další Češi si nechali vložit do těla čip

Další Češi si nechali vložit do těla čip