Obsah
1. Novinky v Clojure verze 1.9.0
2. Instalace Clojure 1.9.0 bez použití nástroje Leiningen
3. Instalace využívající nový instalační skript
4. První spuštění interaktivního REPLu
5. Instalace Clojure 1.9.0 s použitím nástroje Leiningen
7. Spuštění interaktivního REPLu
9. Ukázka automatického stažení závislých balíčků
10. Umístění stažených knihoven
11. Projekt závisející na větším množství knihoven
12. Projekt využívající lokální knihovny
13. Nové predikáty v základní knihovně Clojure
14. Otestování nových predikátů
16. Jednoduchá ukázka použití knihovny clojure.spec
17. Nepatrně složitější příklad
18. Repositář s demonstračními příklady
19. Odkazy na předchozí části tohoto seriálu
1. Novinky v Clojure verze 1.9.0
Již na začátku prosince se vývojáři používající programovací jazyk Clojure dočkali nové verze svého oblíbeného nástroje. Vyšla totiž stabilní verze Clojure 1.9.0, která byla tento měsíc následována alfa verzí 1.10.0-alpha4. V dnešním článku se budeme zabývat novinkami, které byly zařazeny do stabilní verze 1.9.0. Již na začátku je nutné říct, že většina novinek se netýká samotného programovacího jazyka, na což jsou ovšem programátoři zvyklí, protože lispovské jazyky s minimalistickou syntaxí a současně s podporou systému maker příliš velké úpravy či vylepšování syntaxe nepotřebují. Ovšem další části celého ekosystému postaveného okolo Clojure je samozřejmě možné různým způsobem vylepšovat. Týká se to jak knihoven, tak i toolingu, tj. různých podpůrných nástrojů používaných při vývoji aplikací, správě projektů, popř. při nasazování aplikací do testovacího či produkčního prostředí.
Mezi největší novinky Clojure 1.9.0 tak patří zařazení knihovny spec do Clojure a současně úprava základních knihoven dodávaných s tímto jazykem takovým způsobem, aby tuto knihovnu podporovaly (spec je sice stále v alfa verzi, ovšem v Clojure světě alfa již znamená dobrou stabilitu). Knihovnu spec je možné využít jak pro přesný popis složitých datových struktur (typicky kombinace slovníků s vektory), tak i pro jejich validaci. Další novinkou, kterou ve verzi 1.9.0 najdeme, je vylepšená podpora pro použití Clojure z příkazového řádku a v neposlední řadě taktéž standardní správce projektů. Ten sice – alespoň prozatím – neobsahuje tolik možností jako oblíbený Leiningen, ovšem pro jednodušší projekty mohou jeho možnosti vývojářům dostačovat. S některými možnostmi nabízenými tímto správcem se seznámíme v osmé až dvanácté kapitole.
java version "1.7.0_79" OpenJDK Runtime Environment (IcedTea 2.5.5) (7u79-2.5.5-0ubuntu0.14.04.2) OpenJDK 64-Bit Server VM (build 24.79-b02, mixed mode)
openjdk version "1.8.0_151" OpenJDK Runtime Environment (build 1.8.0_151-b12) OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)
2. Instalace Clojure 1.9.0 bez použití nástroje Leiningen
V této kapitole si ukážeme, jakým způsobem je možné nainstalovat programovací jazyk Clojure 1.9.0 i se standardními podpůrnými nástroji. Přitom se zaměříme na situaci, kdy se z různých důvodů vývojář rozhodne, že nepoužije nástroj Leiningen. Pro naprostou většinu projektů je sice stále doporučováno Leiningen použít, ovšem mohou existovat situace, kdy to není možné. V těchto situacích máme hned několik možností, jak Clojure 1.9.0 nainstalovat.
První volbou, která se nám nabízí (a která není nikde popsána :-), je ruční instalace. Pokud se tedy rozhodnete si sami řídit všechny kroky instalace, postačuje si stáhnout soubor nazvaný clojure-1.9.0-javadoc.jar z adresáře https://repo1.maven.org/maven2/org/clojure/clojure/1.9.0/. Tento soubor obsahuje jak samotný jazyk Clojure (překladač do bajtkódu JVM, runtime i vlastní smyčku REPL), tak i základní knihovny a dokonce i jejich zdrojové kódy. Pro stažení do lokálního adresáře postačí nástroj wget (popř. curl -O):
$ wget http://repo1.maven.org/maven2/org/clojure/clojure/1.9.0/clojure-1.9.0.jar Resolving repo1.maven.org (repo1.maven.org)... 151.101.12.209 Connecting to repo1.maven.org (repo1.maven.org)|151.101.12.209|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 3688794 (3,5M) [application/java-archive] Saving to: ‘clojure-1.9.0.jar’ 100%[======================================================] 3 688 794 1,70MB/s in 2,1s 2018-02-20 21:49:35 (1,70 MB/s) - ‘clojure-1.9.0.jar’ saved [3688794/3688794]
Navíc ještě – což je novinka, která se poprvé objevila právě ve verzi 1.9.0 – musíte stáhnout knihovnu spec:
$ wget https://repo1.maven.org/maven2/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar --2018-02-20 22:01:14-- https://repo1.maven.org/maven2/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar Resolving repo1.maven.org (repo1.maven.org)... 151.101.12.209 Connecting to repo1.maven.org (repo1.maven.org)|151.101.12.209|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 591287 (577K) [application/java-archive] Saving to: ‘spec.alpha-0.1.143.jar’ 100%[======================================================] 591 287 478KB/s in 1,2s 2018-02-20 22:01:16 (478 KB/s) - ‘spec.alpha-0.1.143.jar’ saved [591287/591287]
V pracovním adresáři tedy budeme mít dva Java archivy:
- clojure-1.9.0.jar
- spec.alpha-0.1.143.jar
Spuštění interaktivní smyčky REPL bude vypadat jinak, než v předchozích verzích, protože je nutné specifikovat cestu k Java archivu s knihovnou spec:
$ java -cp spec.alpha-0.1.143.jar:clojure-1.9.0.jar clojure.main Clojure 1.9.0 user=>
3. Instalace využívající nový instalační skript
Existuje však i mnohem snadnější varianta instalace Clojure verze 1.9.0. Pro tuto verzi totiž byl připraven instalační skript, který sám stáhne všechny potřebné archivy a rozbalí je do správných adresářů v systému. Nejprve si tedy tento skript stáhneme do pracovního adresáře:
$ wget https://download.clojure.org/install/linux-install-1.9.0.326.sh % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 765 100 765 0 0 3759 0 --:--:-- --:--:-- --:--:-- 3768
Následně si skript pro jistotu prohlédněte, abyste zjistili, co přesně dělá (je to jen zhruba dvacet řádků). Skript totiž budeme spouštět s rootovskými právy a to z toho důvodu, že se soubory budou rozbalovat do adresáře /usr/local. Po spuštění skriptu s právy roota se provede automatické stažení potřebných archivů a jejich rozbalení:
$ sudo bash linux-install-1.9.0.326.sh Downloading and expanding tar % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 17.0M 100 17.0M 0 0 21.7M 0 --:--:-- --:--:-- --:--:-- 21.7M Installing libs into /usr/local/lib/clojure Installing clojure and clj into /usr/local/bin Removing download Use clj -h for help.
Adresář /usr/local byl na mém systému prakticky prázdný (obsahoval jen několik prázdných podadresářů pro manuálové stránky). Po instalaci Clojure 1.9.0 se jeho obsah změnil následovně:
$ tree /usr/local/ /usr/local/ ├── bin │ ├── clj │ └── clojure ├── etc ├── games ├── include ├── lib │ └── clojure │ ├── deps.edn │ ├── example-deps.edn │ └── libexec │ └── clojure-tools-1.9.0.326.jar ├── lib64 ├── libexec ├── sbin ├── share │ ├── applications │ │ └── mimeinfo.cache │ ├── info │ └── man │ ├── man1 │ ├── man1x │ ├── man2 │ ├── man2x │ ├── man3 │ ├── man3x │ ├── man4 │ ├── man4x │ ├── man5 │ ├── man5x │ ├── man6 │ ├── man6x │ ├── man7 │ ├── man7x │ ├── man8 │ ├── man8x │ ├── man9 │ ├── man9x │ └── mann └── src 34 directories, 6 files
4. První spuštění interaktivního REPLu
Před vlastním spuštěním interaktivní smyčky REPL si doinstalujte balíček rlwrap. Ten sice striktně nepotřebujete, ovšem ovládání REPLu nebude tak příjemné (klávesové zkratky, historie příkazového řádku atd.):
$ sudo dnf install rlwrap
alternativně:
$ sudo apt-get install rlwrap
Nyní je již možné spustit REPL, a to (opět nově!) příkazem clj. Povšimněte si, že se teprve nyní doinstalují další závislosti, především pak samotný Clojure:
$ clj Downloading: org/clojure/clojure/1.9.0/clojure-1.9.0.jar from https://repo1.maven.org/maven2/ Downloading: org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar from https://repo1.maven.org/maven2/ Downloading: org/clojure/core.specs.alpha/0.1.24/core.specs.alpha-0.1.24.jar from https://repo1.maven.org/maven2/ Clojure 1.9.0 user=>
REPL ukončíme klasicky:
[Ctrl+D]
Každé další spuštění interpreteru již bude rychlejší, protože se samozřejmě již nebudou žádné další závislosti stahovat. Ostatně si to můžeme vyzkoušet:
$ clj Clojure 1.9.0 user=>
Poznámka: ve skutečnosti je clj poměrně mocný nástroj s mnoha přepínači a příkazy:
$ clj --help Usage: clojure [dep-opt*] [init-opt*] [main-opt] [arg*] clj [dep-opt*] [init-opt*] [main-opt] [arg*] The clojure script is a runner for Clojure. clj is a wrapper for interactive repl use. These scripts ultimately construct and invoke a command-line of the form: java [java-opt*] -cp classpath clojure.main [init-opt*] [main-opt] [arg*] The dep-opts are used to build the java-opts and classpath: -Jopt Pass opt through in java_opts, ex: -J-Xmx512m -Oalias... Concatenated jvm option aliases, ex: -O:mem -Ralias... Concatenated resolve-deps aliases, ex: -R:bench:1.9 -Calias... Concatenated make-classpath aliases, ex: -C:dev -Malias... Concatenated main option aliases, ex: -M:test -Aalias... Concatenated aliases of any kind, ex: -A:dev:mem -Sdeps EDN Deps data to use as the final deps file -Spath Compute classpath and echo to stdout only -Srepro Use only the local deps.edn (ignore other config files) -Sforce Force recomputation of the classpath (don't use the cache) -Spom Generate (or update existing) pom.xml with deps and paths -Stree Print dependency tree -Sresolve-tags Resolve git coordinate tags to shas and update deps.edn -Sverbose Print important path info to console init-opt: -i, --init path Load a file or resource -e, --eval string Eval exprs in string; print non-nil values main-opt: -m, --main ns-name Call the -main function from namespace w/args -r, --repl Run a repl path Run a script from a file or resource - Run a script from standard input -h, -?, --help Print this help message and exit
5. Instalace Clojure 1.9.0 s použitím nástroje Leiningen
Alternativně je možné Clojure 1.9.0 nainstalovat s použitím správce projektů Leiningen. Opět si ukažme, jak to lze provést. Předpokládejme, že již Leiningen používáte s prakticky libovolnou starší verzí Clojure. Nejprve vytvoříme nový projekt, a to příkazem:
lein new app clojure9-test Generating a project called clojure9-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 │ └── clojure9_test │ └── core.clj └── test └── clojure9_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 clojure9-test "0.1.0-SNAPSHOT" :description "Projekt, který zajistí stažení Clojure verze 1.9.0" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.7.0"]] :main ^:skip-aot clojure9-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, 1.7.0 či 1.8.0 používala verze 1.9.0:
(defproject clojure9-test "0.1.0-SNAPSHOT" :description "Projekt, který zajistí stažení Clojure verze 1.9.0" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.9.0"]] :main ^:skip-aot clojure9-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.9.0/clojure-1.9.0.pom from central Retrieving org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.pom from central Retrieving org/clojure/pom.contrib/0.2.2/pom.contrib-0.2.2.pom from central Retrieving org/clojure/core.specs.alpha/0.1.24/core.specs.alpha-0.1.24.pom from central Retrieving org/clojure/clojure/1.9.0/clojure-1.9.0.jar from central Retrieving org/clojure/core.specs.alpha/0.1.24/core.specs.alpha-0.1.24.jar from central Retrieving org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar from central
6. Výsledek instalace
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 (popravdě, vzhledem k množství knihoven už se dostáváme do dependency hell). 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:
$ tree ~/.m2/repository/org/clojure/clojure /home/tester/.m2/repository/org/clojure/clojure ├── 1.2.0 │ ├── clojure-1.2.0.pom │ ├── clojure-1.2.0.pom.sha1 │ └── _maven.repositories ├── 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.3.0-alpha5 │ ├── clojure-1.3.0-alpha5.pom │ ├── clojure-1.3.0-alpha5.pom.sha1 │ └── _maven.repositories ├── 1.3.0-alpha6 │ ├── clojure-1.3.0-alpha6.pom │ ├── clojure-1.3.0-alpha6.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.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 └── 1.9.0 ├── clojure-1.9.0.jar ├── clojure-1.9.0.jar.sha1 ├── clojure-1.9.0.pom ├── clojure-1.9.0.pom.sha1 └── _maven.repositories 11 directories, 45 files
V případě Clojure verze 1.9.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.9.0 total 3628 -rw-r--r-- 1 tester tester 3688794 úno 19 21:11 clojure-1.9.0.jar -rw-r--r-- 1 tester tester 40 úno 19 21:11 clojure-1.9.0.jar.sha1 -rw-r--r-- 1 tester tester 10055 úno 19 21:11 clojure-1.9.0.pom -rw-r--r-- 1 tester tester 40 úno 19 21:11 clojure-1.9.0.pom.sha1 -rw-r--r-- 1 tester tester 180 úno 19 21:11 _maven.repositories
Mezi další nainstalované balíky patří core.spec.alpha a spec.alpha:
$ tree ~/.m2/repository/org/clojure/*spec* /home/tester/.m2/repository/org/clojure/core.specs.alpha └── 0.1.24 ├── core.specs.alpha-0.1.24.jar ├── core.specs.alpha-0.1.24.jar.sha1 ├── core.specs.alpha-0.1.24.pom ├── core.specs.alpha-0.1.24.pom.sha1 └── _maven.repositories /home/tester/.m2/repository/org/clojure/spec.alpha └── 0.1.143 ├── _maven.repositories ├── spec.alpha-0.1.143.jar ├── spec.alpha-0.1.143.jar.sha1 ├── spec.alpha-0.1.143.pom └── spec.alpha-0.1.143.pom.sha1 2 directories, 10 files
7. 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 52784 on host 127.0.0.1 - nrepl://127.0.0.1:52784 REPL-y 0.3.5, nREPL 0.2.6 Clojure 1.9.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 clojure9-test.core=>
V případě, že se zobrazí odlišná verze Clojure, zkontrolujte, zda příkaz opravdu zadáváte z adresáře s projektem vytvořeným v páté kapitole.
Tato forma interaktivní 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. Z tohoto důvodu právě tuto smyčku použijeme v dalším textu při vysvětlování nových možností Clojure 1.9.0.
8. Nový správce projektů
Nejviditelnějším vylepšením Clojure verze 1.9.0 je zcela nový správce projektů a s ním související „univerzální“ skript nazvaný clj, který je umístěný v adresáři /usr/local/bin. Předchozí verze Clojure byly z tohoto pohledu poněkud uživatelsky nepřítulné, protože se interpret (přesněji interaktivní smyčka REPL) spouštěl přes příkaz java, kterému se musela předat cesta k Java archivu clojureXXX.jar. Standardní správce projektů v předchozích verzích zcela chyběl, takže programátoři byli odkázáni na další nástroje, například na skvělý Leiningen. Oba tyto nedostatky jsou nyní, alespoň do určité míry, odstraněny, protože Clojure 1.9.0 obsahuje jak skript clj spustitelný odkudkoli, tak i správu projektů a knihoven, taktéž řízenou přes clj. Nový způsob spuštění interpretru jsme již viděli v předchozích kapitolách:
$ clj Clojure 1.9.0 user=>
Projekt je reprezentován souborem deps.edn, který obsahuje seznam knihoven, jenž jsou nutné pro spuštění projektu. V případě, že například budeme chtít vytvořit projekt používající knihovnu core.matrix, s níž jsme se již na Rootu seznámili, může soubor deps.edn vypadat následovně:
{:deps {net.mikera/core.matrix {:mvn/version "0.62.0"}}}
Vidíme, že je specifikován jak plný název knihovny, tak i způsob jejího stažení – zde konkrétně z Maven repositáře. Konkrétní verzi jsem našel přímo na GitHub repositáři s knihovnou.
Pokud se nacházíte v adresáři se souborem deps.edn, je možné si vypsat všechny knihovny, na kterých projekt závisí, ať již přímo či nepřímo:
$ clj -Stree org.clojure/clojure 1.9.0 org.clojure/spec.alpha 0.1.143 org.clojure/core.specs.alpha 0.1.24 net.mikera/core.matrix 0.62.0 org.clojure/tools.macro 0.1.5
Vidíme, že se závislosti zobrazí formou stromu.
Můžeme si samozřejmě vyzkoušet i projekt se složitějšími závislostmi. Pro tvorbu webových aplikací je stále populární framework Ring, s nímž jsme se již taktéž seznámili. Zkusme si tedy vytvořit projekt s touto závislostí:
{:deps {ring/ring-core {:mvn/version "1.3.2"}}}
Následně můžeme vypsat strom závislostí, který podle očekávání bude vypadat zcela odlišně:
$ clj -Stree org.clojure/clojure 1.9.0 org.clojure/core.specs.alpha 0.1.24 org.clojure/spec.alpha 0.1.143 ring/ring-core 1.3.2 commons-fileupload/commons-fileupload 1.3 commons-io/commons-io 2.4 clj-time/clj-time 0.6.0 joda-time/joda-time 2.2 crypto-random/crypto-random 1.2.0 commons-codec/commons-codec 1.6 ring/ring-codec 1.0.0 crypto-equality/crypto-equality 1.0.0 org.clojure/tools.reader 0.8.1
9. Ukázka automatického stažení závislých balíčků
Vraťme se nyní k našemu prvnímu projektu, u něhož jsme specifikovali závislost na knihovně core.matrix. Pokud se přepneme do adresáře, v němž se nachází soubor deps.edn a spustíme interpret příkazem clj, provede se několik operací:
- Nejprve se zjistí, které knihovny (a jejich případné závislosti) je nutné stáhnout.
- Následně se všechny potřebné knihovny skutečně stáhnou a uloží do adresáře~/.m2 (Javisté používající Maven tento adresář jistě znají).
- Nastaví se CLASSPATH.
- Teprve poté se spustí interpret, tj. interaktivní smyčka REPL.
Ostatně o průběhu těchto kroků se můžeme snadno přesvědčit:
$ clj Downloading: net/mikera/core.matrix/0.62.0/core.matrix-0.62.0.pom from https://clojars.org/repo/ Downloading: net/mikera/clojure-pom/0.6.0/clojure-pom-0.6.0.pom from https://clojars.org/repo/ Downloading: net/mikera/mikera-pom/0.6.0/mikera-pom-0.6.0.pom from https://repo1.maven.org/maven2/ Downloading: org/sonatype/oss/oss-parent/9/oss-parent-9.pom from https://repo1.maven.org/maven2/ Downloading: org/clojure/tools.macro/0.1.5/tools.macro-0.1.5.pom from https://repo1.maven.org/maven2/ Downloading: net/mikera/core.matrix/0.62.0/core.matrix-0.62.0.jar from https://clojars.org/repo/ Downloading: org/clojure/tools.macro/0.1.5/tools.macro-0.1.5.jar from https://repo1.maven.org/maven2/ Clojure 1.9.0
Jakmile se objeví výzva interaktivní smyčky REPL, můžeme začít používat funkce a makra deklarovaná v knihovně core.matrix, například:
(use 'clojure.core.matrix) (use 'clojure.core.matrix.operators) nil user=> (let [M (matrix [[1 2] [3 4]]) v (matrix [1 2])] (pm M) (pm v) (pm (* v 2)) (pm (mul M v)) (pm (* M M)) (pm (inner-product M v))) [[1 2] [3 4]] [1 2] [2 4] [[1 4] [3 8]] [[1 4] [9 16]] [5 11] nil
Poznámka: zajímavé je, že stejným způsobem vlastně proběhla samotná instalace Clojure. Pokud se vrátíme do kapitoly s popisem instalace přes nový skript, je patrné, že se Java archiv s Clojure stáhnul až při prvním spuštění skriptu clj. To je zabezpečeno souborem /usr/local/lib/clojure/deps.edn, který vypadá následovně:
{ :paths ["src"] :deps { org.clojure/clojure {:mvn/version "1.9.0"} } :aliases { :deps {:extra-deps {org.clojure/tools.deps.alpha {:mvn/version "0.5.351"}}} :test {:extra-paths ["test"]} } :mvn/repos { "central" {:url "https://repo1.maven.org/maven2/"} "clojars" {:url "https://clojars.org/repo"} } }
10. Umístění stažených knihoven
Všechny stažené knihovny, na nichž projekty závisí, jsou umístěny do adresáře ~/.m2/repository/. Například výše uvedenou knihovnu core.matrix nalezneme v podadresáři net:
$ tree ~/.m2/repository/net/ /home/tester/.m2/repository/net/ └── mikera ├── clojure-pom │ └── 0.6.0 │ ├── clojure-pom-0.6.0.pom │ ├── clojure-pom-0.6.0.pom.sha1 │ └── _remote.repositories ├── core.matrix │ └── 0.62.0 │ ├── core.matrix-0.62.0.jar │ ├── core.matrix-0.62.0.jar.sha1 │ ├── core.matrix-0.62.0.pom │ ├── core.matrix-0.62.0.pom.sha1 │ └── _remote.repositories └── mikera-pom └── 0.6.0 ├── mikera-pom-0.6.0.pom ├── mikera-pom-0.6.0.pom.sha1 └── _remote.repositories 7 directories, 11 files
Konkrétní obsah tohoto podadresáře se může lišit podle toho, jaké knihovny jste již použili pro jiné projekty. Například ve chvíli, kdy byla použita i starší verze core.matrix, může adresář vypadat odlišně:
$ tree ~/.m2/repository/net/ /home/tester/.m2/repository/net/ └── mikera ├── clojure-pom │ └── 0.6.0 │ ├── clojure-pom-0.6.0.pom │ ├── clojure-pom-0.6.0.pom.sha1 │ └── _remote.repositories ├── core.matrix │ ├── 0.60.0 │ │ ├── core.matrix-0.60.0.jar │ │ ├── core.matrix-0.60.0.jar.sha1 │ │ ├── core.matrix-0.60.0.pom │ │ ├── core.matrix-0.60.0.pom.sha1 │ │ └── _remote.repositories │ └── 0.62.0 │ ├── core.matrix-0.62.0.jar │ ├── core.matrix-0.62.0.jar.sha1 │ ├── core.matrix-0.62.0.pom │ ├── core.matrix-0.62.0.pom.sha1 │ └── _remote.repositories └── mikera-pom └── 0.6.0 ├── mikera-pom-0.6.0.pom ├── mikera-pom-0.6.0.pom.sha1 └── _remote.repositories 8 directories, 16 files
11. Projekt závisející na větším množství knihoven
V této kapitole si ukážeme nepatrně složitější projekt, v němž budeme vyžadovat použití dvou knihoven. Kromě již zmíněné knihovny core.matrix ještě použijeme knihovnu clj-time, která je velmi užitečná, protože obsahuje funkce a makra pro práci s časovými údaji, jejich převod na řetězec atd. atd. Soubor deps.edn bude rozšířen následujícím způsobem:
{:deps {net.mikera/core.matrix {:mvn/version "0.62.0"} clj-time {:mvn/version "0.14.2"}}}
Při prvním spuštění interpretru se samozřejmě všechny potřebné balíčky stáhnou:
$ clj Downloading: clj-time/clj-time/0.14.2/clj-time-0.14.2.pom from https://clojars.org/repo/ Downloading: joda-time/joda-time/2.9.7/joda-time-2.9.7.pom from https://repo1.maven.org/maven2/ Downloading: clj-time/clj-time/0.14.2/clj-time-0.14.2.jar from https://clojars.org/repo/ Downloading: joda-time/joda-time/2.9.7/joda-time-2.9.7.jar from https://repo1.maven.org/maven2/ Clojure 1.9.0
Hlavní modul projektu bude uložen v podadresáři src a bude se jmenovat main.clj, což současně odpovídá i názvu jmenného prostoru nastaveného deklarací (ns). Dále si povšimněte existence funkce -main, která je vstupním bodem do aplikace:
(ns main) (require '[clj-time.core :as t]) (require '[clj-time.format :as f]) (require '[clojure.core.matrix :as m]) (require '[clojure.core.matrix.operators :as o]) (defn matrix-tests [] (let [M (m/matrix [[1 2 3] [4 5 6] [7 8 9]]) v (m/matrix [1/2 2/3 3/4])] (m/pm M) (m/pm v) (m/pm (o/* v 2)) (m/pm (m/mul M v)) (m/pm (o/* M M)) (m/pm (m/inner-product M v)))) (defn time-str "Returns a string representation of a datetime in the local time zone." [dt] (f/unparse (f/with-zone (f/formatter "hh:mm aa") (t/default-time-zone)) dt)) (defn -main [] (println "Hello world, the time is" (time-str (t/now))) (matrix-tests))
Projekt opět spustíme skriptem clj, musíme mu však předat název jmenného prostoru, v němž se nachází funkce -main, která má být spuštěna:
$ clj -m main Hello world, the time is 04:59 PM [[1 2 3] [4 5 6] [7 8 9]] [0.500 0.667 0.750] [1 1.333 1.500] [[0.500 1.333 2.250] [ 2 3.333 4.500] [3.500 5.333 6.750]] [[ 1 4 9] [16 25 36] [49 64 81]] [4.083 9.833 15.583]
12. Projekt využívající lokální knihovny
Jen nepatrně složitější jsou projekty využívající lokální knihovnu či knihovny. Ukažme si napřed strukturu takového projektu, který se skládá z hlavního modulu main, lokální knihovny matrix a druhé lokální knihovny time_utils:
├── main │ ├── deps.edn │ └── src │ └── main.clj ├── matrix │ ├── deps.edn │ └── src │ └── matrix.clj └── time_utils ├── deps.edn └── src └── time_utils.clj
Povšimněte si, že každá lokální knihovna má naprosto stejnou strukturu jako celý projekt. Jednotlivé soubory deps.edn vypadají následovně (v pořadí, v jakém jsou uvedeny ve stromu).
Hlavní modul používá obě lokální knihovny, takže selektor obsahuje keyword :local/root s cestou ke knihovnám (může být relativní i absolutní):
{:deps {time-utils {:local/root "../time_utils/"} matrix {:local/root "../matrix/"}}}
Lokální knihovna matrix má tuto závislost:
{:deps {net.mikera/core.matrix {:mvn/version "0.62.0"}}}
Lokální knihovna time_utils má jinou závislost:
{:deps {clj-time {:mvn/version "0.14.2"}}}
Ve zdrojovém kódu hlavního modulu můžeme přistupovat k lokálním knihovnám stejně, jako ke knihovnám externím:
(ns main) (require '[time-utils :as t]) (require '[matrix :as m]) (defn -main [] (println "Hello world, the time is" (t/time-str (t/now))) (m/matrix-tests))
Spuštění projektu se provádí z podadresáře main:
$ clj -m main Hello world, the time is 06:17 PM [[1 2 3] [4 5 6] [7 8 9]] [0.500 0.667 0.750] [1 1.333 1.500] [[0.500 1.333 2.250] [ 2 3.333 4.500] [3.500 5.333 6.750]] [[ 1 4 9] [16 25 36] [49 64 81]] [4.083 9.833 15.583]
13. Nové predikáty v základní knihovně Clojure
V souvislosti s knihovnou spec popsanou níže bylo do standardní knihovny přidáno poměrně velké množství nových predikátů. S predikáty jsme se již setkali a není na nich nic složitého – jedná se totiž o běžné funkce s jediným parametrem, které pouze na základě hodnoty svého parametru vrací pravdivostní hodnotu true či false (teoreticky též nil). Standardní predikát poznáme snadno, protože jméno funkce končí otazníkem.
Stávající predikáty, resp. jejich významná část:
# | Predikát | Význam |
---|---|---|
1 | nil? | test, zda je předaná hodnota rovna literálu nil |
2 | true? | test, zda je předaná hodnota rovna literálu true |
3 | false? | test, zda je předaná hodnota rovna literálu false |
4 | number? | test na číslo (libovolného typu) |
5 | integer? | test na celé číslo |
6 | ratio? | test na zlomek (nikoli na obecné desetinné číslo) |
7 | float? | test na desetinné číslo |
8 | decimal? | test na hodnotu typu BigDecimal |
9 | even? | test na sudou hodnotu |
10 | odd? | test na lichou hodnotu |
11 | pos? | test na kladnou hodnotu |
12 | neg? | test na zápornou hodnotu |
13 | zero? | test na nulu |
14 | keyword? | test, zda je předaná hodnota typu klíčové heslo |
15 | symbol? | test, zda je předaná hodnota typu symbol |
16 | char? | test, zda je předaná hodnota typu char |
17 | string? | test, zda je předaná hodnota typu řetězec |
18 | seq? | test, zda je předaná hodnota typu sekvence |
Predikáty ve jmenném prostoru clojure.string zavedené v rámci Clojure 1.8.0:
# | Predikát | Význam |
---|---|---|
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 |
Nové předikáty v Clojure 1.9.0 se většinou týkají testu, jaký typ má hodnota předaná do predikátu:
# | Predikát | Význam |
---|---|---|
1 | boolean? | test na typ hodnoty (true/false) |
2 | int? pos-int? neg-int? nat-int? | test na typ proměnné + její hodnotu, viz další text |
3 | double? | test na typ hodnoty |
4 | ident? simple-ident? qualified-ident? | test, zda je hodnota symbolem či keywordem |
5 | simple-symbol? qualified-symbol? | test, zda je hodnota symbolem |
6 | simple-keyword? qualified-keyword? | test, zda je hodnota keywordem |
7 | bytes? | test, zda je typ hodnoty bytovým polem |
8 | indexed? | test, zda jsou prvky hodnoty indexovatelné (viz další text) |
9 | uuid? uri? | test, zda je hodnota typu UUID (vhodné pro webové služby atd.) |
10 | seqable? | test, zda lze na hodnotu použít funkci seq |
11 | any? | predikát, který vždy vrací true |
14. Otestování nových predikátů
Některé nové predikáty si můžeme snadno otestovat, a to interaktivně ve smyčce REPL.
Predikát testující, jestli je mu předána pravdivostní hodnota:
clojure9-test.core=> (boolean? nil) false clojure9-test.core=> (boolean? true) true clojure9-test.core=> (boolean? false) true clojure9-test.core=> (boolean? "Hello") false clojure9-test.core=> (boolean? :else) false
Test na celé číslo:
clojure9-test.core=> (int? 0) true clojure9-test.core=> (int? 42) true clojure9-test.core=> (int? -42) true clojure9-test.core=> (int? 0.5) false clojure9-test.core=> (int? 1/2) false
Test na kladné číslo (bez nuly):
clojure9-test.core=> (pos-int? 0) false clojure9-test.core=> (pos-int? 42) true clojure9-test.core=> (pos-int? -42) false
Test na záporné číslo (bez nuly):
clojure9-test.core=> (neg-int? 0) false clojure9-test.core=> (neg-int? 42) false clojure9-test.core=> (neg-int? -42) true
Test na přirozené číslo (kladná čísla včetně nuly):
clojure9-test.core=> (nat-int? 0) true clojure9-test.core=> (nat-int? 42) true clojure9-test.core=> (nat-int? -42) false
Test na číslo s desetinnou tečkou:
clojure9-test.core=> (double? 0) false clojure9-test.core=> (double? 0.) true clojure9-test.core=> (double? 1/2) false clojure9-test.core=> (double? 1e10) true
Otestování, zda je možné přistupovat k prvkům předávané hodnoty pomocí indexu:
clojure9-test.core=> (indexed? [1 2 3]) true clojure9-test.core=> (indexed? '(1 2 3)) false clojure9-test.core=> (indexed? {1 "jedna" 2 "dve" 3 "tri"}) false clojure9-test.core=> (indexed? #{1 2 3}) false clojure9-test.core=> (indexed? nil) false
Sekvence se považují za neindexovatelné, i když vznikly z vektoru:
clojure9-test.core=> (map inc [1 2 3]) (2 3 4) clojure9-test.core=> (indexed? (map inc [1 2 3])) false
Test, zda je možné na hodnotu aplikovat funkci seq. Povšimněte si, že pro nil se také vrací true:
clojure9-test.core=> (seqable? 0) false clojure9-test.core=> (seqable? true) false clojure9-test.core=> (seqable? false) false clojure9-test.core=> (seqable? "string") true clojure9-test.core=> (seqable? nil) true clojure9-test.core=> (seqable? [1 2 3]) true clojure9-test.core=> (seqable? '(1 2 3)) true clojure9-test.core=> (seqable? {1 "jedna" 2 "dva" 3 "tri"}) true clojure9-test.core=> (seqable? #{1 2 3}) true clojure9-test.core=> (seqable? (map inc [1 2 3])) true
Poslední predikát vždy vrací true:
clojure9-test.core=> (any? nil) true clojure9-test.core=> (any? true) true clojure9-test.core=> (any? [1 2 3]) true
15. Knihovna clojure.spec
Již v úvodních odstavcích jsme se zmínili o tom, že do Clojure verze 1.9.0 byla přidána i knihovna nazvaná spec; ta je dokonce tak provázaná s vlastním runtime systémem, že bez této knihovny nepůjde spustit interpret. K čemu se tedy spec může použít? Jedná se o nástroj použitelný pro deklaraci vlastností (uživatelských) datových typů a následně pro validaci dat. Samotné Clojure, resp. běžné funkce, většinou neprovádí kontrolu, jaká data jsou předávána; na rozdíl od staticky typovaných programovacích jazyků. Základní typovou kontrolu sice bylo možné „vynutit“ i v předchozích verzích Clojure, ovšem jen v omezené míře. Díky knihovně spec je možné datové struktury popsat naprosto přesně s použitím logických spojek, deklaraci opakování atributu a taktéž predikátů (predikáty jsou samozřejmě uživatelsky definovatelné).
Validaci dat je možné použít v mnoha oblastech. Představme si například webovou službu, která přijme data ve formátu JSON, převede je knihovní funkcí do nativní datové struktury (typicky do slovníku seznamů či hierarchicky uspořádaných slovníků) a následně provede validaci této struktury, ovšem nikoli programově (testováním jednotlivých atributů), ale na základě deklarativního popisu této struktury. Například můžeme specifikovat, že v atributu „price“ bude nezáporné číslo menší než 100000, v atributu „valid_from“ musí být uložen řetězec odpovídající skutečnému datu (to už nelze otestovat primitivním regulárním výrazem, ale složitějším predikátem) a v atributu „login“ bude buď nick uživatele nebo bude tento atribut obsahovat nil (popř. alternativně nebude existovat vůbec).
Jednodušším příkladem může být již v předchozích kapitolách zmíněný projektový soubor deps.edn. Jedná se sice o běžný slovník serializovaný do textového souboru, ovšem při jeho zpracování vyžadujeme určitou strukturu. A právě tu lze relativně snadno popsat a následně zkontrolovat přes knihovnu spec.
Možnosti knihovny spec jsou poměrně velké, takže se jí budeme zabývat v samostatném článku, ovšem základní deklarace si vyzkoušíme již dnes.
16. Jednoduchá ukázka použití knihovny clojure.spec
Zkusme si nyní ukázat alespoň základy, na nichž je knihovna clojure.spec postavena. Všechny další příklady jsou spouštěny v interaktivní smyčce REPL a části zadávané programátorem jsou zobrazeny tučným písmem.
Nejprve načteme knihovnu clojure.spec s využitím funkce require (pro jednoduchost nepoužijeme makro ns):
clojure9-test.core=> (require '[clojure.spec.alpha :as spec]) nil
Následně můžeme vytvořit specifikaci pro kontrolu dat a uložit ji do tzv. centrálního registru. To se provádí zavoláním makra def z knihovny clojure.spec.alpha. Předchozím příkazem require jsme pro tuto knihovnu vytvořili alias nazvaný spec, takže makro def zavoláme (spec/def …). Makru musíme předat jméno specifikace (typicky keyword) a vlastní deklaraci specifikace. V ní máme napsáno, že se má kontrolovat, zda je předaná hodnota typu celé číslo a současně (spec/and) zda je toto číslo sudé.
clojure9-test.core=> (spec/def ::even? (spec/and integer? even?)) :clojure9-test.core/even? clojure9-test.core=> (spec/def ::odd? (spec/and integer? odd?)) :clojure9-test.core/odd?
K oběma specifikacím se automaticky vytvořila dokumentace:
clojure9-test.core=> (doc ::even?) ------------------------- :clojure9-test.core/even? Spec (and integer? even?) nil
Validace, zda konkrétní hodnota odpovídá specifikaci, se provede funkcí spec/conform. V našem nejjednodušším případě se buď vrátí původní hodnota nebo keyword :clojure.spec.alpha/invalid:
clojure9-test.core=> (spec/conform ::even? 0) 0 clojure9-test.core=> (spec/conform ::even? 1) :clojure.spec.alpha/invalid clojure9-test.core=> (spec/conform ::even? 2) 2
Alternativně lze jen testovat validitu:
clojure9-test.core=> (spec/valid? ::even? 0) true clojure9-test.core=> (spec/valid? ::even? 1) false clojure9-test.core=> (spec/valid? ::even? 2) true
Pokud je nějaký vstup nevalidní a my potřebujeme zjistit proč, nabízí se funkce explain:
clojure9-test.core=> (spec/explain even? 1) val: 1 fails predicate: :clojure.spec.alpha/unknown nil
17. Nepatrně složitější příklad
Kromě klauzule and je možné predikáty spojit klauzulí or. V tomto případě je však nutné použít sudý počet parametrů, přičemž se před každým predikátem zadává identifikátor, který predikát pojmenovává. Je tomu tak z toho důvodu, že když bude specifikace splněna, budeme chtít vědět, díky jakému predikátu se tak stalo. U klauzule and to nebylo nutné, protože tam musely být splněny všechny predikáty:
clojure9-test.core=> (spec/def ::not-zero? (spec/or :positive-part pos-int? :negative-part neg-int?)) :clojure9-test.core/not-zero?
Předchozí specifikace je splněna pro všechna celá čísla rozdílná od nuly. Ověříme si to snadno (sledujte hlavně to, jak vypadá návratová hodnota):
clojure9-test.core=> (spec/conform ::not-zero? 0) :clojure.spec.alpha/invalid clojure9-test.core=> (spec/conform ::not-zero? 1) [:positive-part 1] clojure9-test.core=> (spec/conform ::not-zero? -2) [:negative-part -2]
Opět si můžeme ověřit, proč nedošlo k validaci:
clojure9-test.core=> (spec/conform ::not-zero? 0) :clojure.spec.alpha/invalid clojure9-test.core=> (spec/explain ::not-zero? 0) val: 0 fails spec: :clojure9-test.core/not-zero? at: [:positive-part] predicate: pos-int? val: 0 fails spec: :clojure9-test.core/not-zero? at: [:negative-part] predicate: neg-int? nil
Na tyto velmi jednoduché příklady příště navážeme a ukážeme si, jak provádět validaci skutečně složitých hierarchických datových struktur.
18. Repositář s demonstračními příklady
Demonstrační příklady a projekty určené pro Clojure 1.9.0 byly uloženy do repositáře https://github.com/tisnik/clojure-examples:
Příklad | Popis | Odkaz |
---|---|---|
clojure9-test | Leiningen projekt pro instalaci 1.9.0 | https://github.com/tisnik/clojure-examples/tree/master/clojure9-test |
clojure9-deps | pouze ukázka souboru deps.edn | https://github.com/tisnik/clojure-examples/tree/master/clojure9-deps |
clojure9-deps-2 | pouze ukázka souboru deps.edn | https://github.com/tisnik/clojure-examples/tree/master/clojure9-deps-2 |
clojure9-project1 | projekt s externími knihovnami | https://github.com/tisnik/clojure-examples/tree/master/clojure9-project1 |
clojure9-project2 | projekt s lokálními knihovnami | https://github.com/tisnik/clojure-examples/tree/master/clojure9-project2 |
19. 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/ - 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: 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/ - 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/ - Novinky v Clojure verze 1.8.0
http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/ - Asynchronní programování v Clojure s využitím knihovny core.async
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async/ - Asynchronní programování v Clojure s využitím knihovny core.async (pokračování)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-pokracovani/ - Asynchronní programování v Clojure s využitím knihovny core.async (dokončení)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-dokonceni/ - Vytváříme IRC bota v programovacím jazyce Clojure
http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/ - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Multimetody v Clojure aneb polymorfismus bez použití OOP
https://www.root.cz/clanky/multimetody-v-clojure-aneb-polymorfismus-bez-pouziti-oop/ - Práce s externími Java archivy v programovacím jazyku Clojure
https://www.root.cz/clanky/prace-s-externimi-java-archivy-v-programovacim-jazyku-clojure/ - Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/ - Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
https://www.root.cz/clanky/programovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/
20. Odkazy na Internetu
- Zip archiv s Clojure 1.9.0
http://repo1.maven.org/maven2/org/clojure/clojure/1.9.0/clojure-1.9.0.zip - Clojure 1.9 is now available
https://clojure.org/news/2017/12/08/clojure19 - Deps and CLI Guide
https://clojure.org/guides/deps_and_cli - Changes to Clojure in Version 1.9
https://github.com/clojure/clojure/blob/master/changes.md - clojure.spec – Rationale and Overview
https://clojure.org/about/spec - 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 - 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