Hlavní navigace

Novinky v Clojure verze 1.9.0

Pavel Tišnovský

Na konci minulého roku jsme se dočkali další verze jazyka Clojure. Mezi novinky ve verzi 1.9.0 patří vylepšené nástroje ovládané z CLI, standardní správce projektů a knihovna spec pro popis a validaci datových struktur.

Doba čtení: 35 minut

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

6. Výsledek instalace

7. Spuštění interaktivního REPLu

8. Nový správce projektů

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ů

15. Knihovna clojure.spec

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

20. Odkazy na Internetu

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édvanácté kapitole.

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 6, tak i novější verze 7 či 8. Já jsem v dnešním článku vše testoval na verzi 7 i 8, sedmičku na Mintu a osmičku na Fedoře:
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/ma­ven2/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:

  1. clojure-1.9.0.jar
  2. 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.

Poznámka: samotný projekt je možné bez obav smazat, protože jeho jedinou úlohou bylo nainstalovat Clojure 1.9.0 do adresáře ~/.m2 a otestovat REPL.

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"}}}
Poznámka: soubory EDN jsou vlastně plnohodnotnými zdrojovými kódy Clojure, až na ten rozdíl, že většinou obsahují pouze data a nikoli volání funkcí či dokonce jejich deklarace. Jedná se tedy o obdobu formátu JSON, který je sice používán i v komunitě vývojářů používajících Clojure, ovšem z pohledu tohoto jazyka se nejedná o nativní formát.

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í:

  1. Nejprve se zjistí, které knihovny (a jejich případné závislosti) je nutné stáhnout.
  2. 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í).
  3. Nastaví se CLASSPATH.
  4. 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

  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. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/
  35. 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/
  36. 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/
  37. Programovací jazyk Clojure a práce s Gitem
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/
  38. 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/
  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/
  48. Novinky v Clojure verze 1.8.0
    http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/
  49. 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/
  50. 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/
  51. 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/
  52. Vytváříme IRC bota v programovacím jazyce Clojure
    http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/
  53. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  54. Multimetody v Clojure aneb polymorfismus bez použití OOP
    https://www.root.cz/clanky/multimetody-v-clojure-aneb-polymorfismus-bez-pouziti-oop/
  55. 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/
  56. Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
    https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/
  57. Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
    https://www.root.cz/clanky/pro­gramovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/

20. Odkazy na Internetu

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