Hlavní navigace

Programovací jazyk Clojure 17: využití standardních maker v praxi

Pavel Tišnovský 2. 10. 2012

V dnešní části seriálu o vlastnostech programovacího jazyka Java i JVM se již naposledy budeme zabývat popisem makrosystému programovacího jazyka Clojure. Popíšeme si některá makra, která vývojáři tvořící aplikace v jazyce Clojure využívají v podstatě každý den, i když si někdy neuvědomují, že volají makra a nikoli běžné funkce či speciální formy.

Obsah

1. Programovací jazyk Clojure 17: využití standardních maker v praxi

2. Makro comment

3. Makra when a when-not

4. Makro if-not

5. Univerzální podmíněné provádění příkazů s využitím makra cond

6. Makro while další poněkud skrytá „nefunkcionální“ řídicí konstrukce

7. Makro dotimes: další příklad použití tail rekurze v praxi

8. Idiom with-* používaný v programovacích jazycích odvozených od LISPu

9. Odkazy na Internetu

1. Programovací jazyk Clojure 17: využití maker v praxi

V dnešní části seriálu o programovacím jazyce Java i o virtuálním stroji Javy (JVM) dokončíme popis makrosystému jazyka Clojure postaveného nad JVM. V předchozích dvou částech tohoto seriálu jsme si řekli, jakým způsobem jsou makra aplikována (ještě před pokusem o vyhodnocení formy) a na několika demonstračních příkladech jsme si ukázali tvorbu vlastních uživatelských maker, při jejichž zápisu jsme používali takzvaná reader makra nazvaná „syntax-quote“ (zapisováno pomocí zpětného apostrofu), „unqote“ (zapisováno znakem tilda před symbolem) a „unquote-splicing“ (zapisováno znakem tilda následovaného zavináčem). Ovšem i přes možnost použití těchto znaků se speciálním významem je tvorba uživatelských maker poměrně složitá záležitost, protože jejich tvůrci musí zajistit správnou funkci makra i v různých mezních případech – makro je například zavoláno bez parametrů, jeho parametrem jsou jen prázdné závorky namísto očekávaného seznamu příkazů atd.

Nicméně makrosystém programovacího jazyka Clojure je možné využít i bez toho, aby musel vývojář vytvářet svá vlastní uživatelská makra – může totiž využít sadu maker dodávanou jako takřka nedílnou součást samotného Clojure. Některá dále popisovaná makra jsou totiž definována v souboru core.clj, jenž obsahuje definice zcela základních funkcí i maker, bez nichž by v podstatě nebylo možné prakticky používat smyčku REPL (teoreticky by to možné sice bylo, ale čitelnost takto vytvořených programů by nebyla vysoká). U všech dále popisovaných maker bude uvedena i jejich definice, protože právě na příkladu standardních maker se můžeme přiučit nejenom to, jak se mají vyvářet uživatelská makra, ale dozvíme se i základní informace o interní struktuře smyčky REPL. Taktéž si ukážeme některé idiomy používané v mnoha LISPovských programovacích jazycích (v samotném LISPu, Scheme atd.). Například se zmíníme o idiomu (Javisté by možná řekli „o návrhovém vzoru“) with-, jenž lze použít v mnoha místech aplikace, zejména tam, kde se pracuje s externím zdrojem (nebo naopak cílem) dat.

V navazujících kapitolách budou popsána následující standardní makra:

Makro Kapitola
comment 2
when 3
when-not 3
if-not 4
cond 5
while 6
dotimes 7
with-* 8

2. Makro comment

Jedno z nejjednodušších standardních maker definovaných v souboru core.clj se jmenuje comment. Jméno tohoto makra velmi přesně vystihuje, k čemu může být využíváno: do makra comment je totiž možné uzavřít prakticky libovolnou část programu, která bude makrem „sežrána“ (samozřejmě v čase načítání forem) a nebude tedy docházet k pokusu o vyhodnocení takto obaleného bloku. Jedinou podmínkou, kterou musí vývojář používající makro comment v každém případě dodržet, je nutnost vybalancování pravých a levých kulatých závorek v bloku, který je makrem comment obalen. Důvod je prostý – objekt reader totiž musí mít možnost určit, kde volání makra comment končí. Definice tohoto makra je skutečně velmi jednoduchá, protože makro comment očekává libovolné množství parametrů ([& body]), které nejsou žádným způsobem dále použity ani vyhodnocovány, protože tělo makra je prázdné:

; zdrojový kód makra comment
(defmacro comment
    "Ignores body, yields nil"
    {:added "1.0"}
    [& body])

Na druhém řádku definice makra comment je zapsána dokumentace (obdoba Javadocu), na řádku třetím pak metadata o tom, kdy bylo toto makro do jazyka Clojure přidáno. Následuje příklad použití makra comment, který asi nepotřebuje další podrobnější vysvětlení:

; zakomentování formy
user=> (comment (println "Hello world!"))
nil
 
 
; expanze makra comment je vždy stejná:
; ... transformuje jakoukoli formu na nil
user=> (macroexpand-1 '(comment (println "Hello world!")))
nil
 
 
; zakomentování volání jednoduché funkce
user=> (comment (* (6 7)))
nil
 
 
; zakomentovat lze i volání neexistující funkce
; ... nedojde k chybě, protože se vyhodnocení neuskuteční
user=> (comment (foo 6 7))
nil
 
 
; pozor si musíme dát pouze na správné vybalancování závorek
; ... zde přebývá pravá složená závorka
user=> (comment (println "Hello world!")))
nil
RuntimeException Unmatched delimiter: )  clojure.lang.Util.runtimeException (Util.java:170)
 
 
user=>

3. Makra when a when-not

Ve zdrojových kódech aplikací vytvářených v programovacím jazyce Clojure můžeme velmi často narazit na volání maker nazvaných when a when-not. Těmto makrům se předává podmínka zapsaná jako forma (tedy výraz) a poté tělo složené z libovolně dlouhé sekvence forem (příkazů). Obě makra se převedou na vyhodnocení prvního předaného výrazu s tím, že pokud je výraz vyhodnocen na hodnotu true u makra when či naopak na hodnotu false u makra when-not, budou zbývající výrazy vyhodnoceny v takovém pořadí, v jakém jsou zadány. Proč se však vlastně tato makra v praxi používají namísto přímého využití speciální formy if? Je to jednoduché – ve speciální formě if je možné uvést pouze jeden příkaz („tělo podmínky“) vyhodnocený jen tehdy, pokud je hodnota předané podmínky rovna true. Pokud programátor potřebuje uzavřít do podmínky větší množství příkazů, použije právě makra when a when-not, kde se tělo podmínky (seznam výrazů) automaticky uzavírá speciální formou do, která zajistí jejich sekvenční provedení. Navíc se při použití when-not vyhne případné nutnosti negování výrazu (podmínky):

; zdrojový kód makra when
(defmacro when
    "Evaluates test. If logical true, evaluates body in an implicit do."
    {:added "1.0"}
    [test & body]
    (list 'if test (cons 'do body)))
; zdrojový kód makra when-not
(defmacro when-not
    "Evaluates test. If logical false, evaluates body in an implicit do."
    {:added "1.0"}
    [test & body]
        (list 'if test nil (cons 'do body)))

Opět si ukážeme jednoduché příklady použití, včetně expanze maker:

; definice funkce, kterou v makrech when a when-not použijeme
user=> (defn greater-than? [x y] (> x y))
#'user/greater-than?
; příklad použití makra when
; (povšimněte si, že návratovou hodnotou "do"
; je návratová hodnota posledního příkazu)
user=> (when (greater-than? 2 1) (print 2) (print ">") (print 1))
2>1nil
 
 
; expanze makra when vypadá následovně:
user=> (macroexpand-1 '(when (greater-than? 2 1) (print 2) (print ">") (print 1)))
(if (greater-than? 2 1) (do (print 2) (print ">") (print 1)))
 
 
user=>

Makro when-not generuje výraz využívající speciální formu if se třemi parametry: podmínkou, „větví if“ a „větví else“, přičemž „větev if“ obsahuje prázdné tělo – hodnotu nil:

; příklad použití makra when-not
user=> (when-not (greater-than? 2 1) (print 2) (print ">") (print 1))
nil
 
 
; expanze makra when-not
; (je zde patrné, že se jako druhý parametr speciální
;  formy "if" předává vždy nil)
user=> (macroexpand-1 '(when-not (greater-than? 2 1) (print 2) (print ">") (print 1)))
(if (greater-than? 2 1) nil (do (print 2) (print ">") (print 1)))
 
 
user=>

4. Makro if-not

Makra when a when-not popsaná v předchozí kapitole nejsou jedinými standardními makry, které do programovacího jazyka Clojure přidávají další řídicí konstrukce (alespoň z pohledu programátora). Dalším takovým dosti často používaným makrem je makro nazvané if-not, jehož význam je již ze samotného názvu tohoto makra zřejmý – jedná se o negaci funkcionality speciální formy if. Připomeňme si, že speciální formu if lze volat se dvěma či třemi parametry. Pokud je tato forma zavolána s dvojicí parametrů, je první parametr chápán jako podmínka a druhý parametr (jenž samozřejmě musí být platnou formou) je vyhodnocen pouze tehdy, pokud je první parametr vyhodnocen na true. V případě, že je speciální forma if zavolána se třemi parametry, slouží poslední parametr jako náhrada „větve else“, ovšem opět se musí jednat pouze o jediný výraz, což je omezení speciální formy if. Toto omezení se v praxi obchází využitím maker when a when-not (viz předchozí kapitolu).

Zatímco těla všech tří maker, s nimiž jsme se seznámili v předchozí dvojici kapitol, byla velmi jednoduchá, je tělo makra if-not již poněkud komplikovanější, a to ze dvou důvodů. První důvod spočívá v tom, že uživatel toto makro bude moci volat se dvěma či třemi parametry, tudíž je nutné vytvořit „multimakro“ s dvojicí těl (multimakro se zapisuje stejným způsobem jako multifunkce – pro každý počet parametrů je zapsáno zvláštní tělo funkce/makra). Druhý důvod větší složitosti makra if-not je způsoben použitím reader maker „syntax-quote“ (zpětný apostrof) a „unquote“ (tilda), díky nimž lze makro zapsat formou šablony, což je doporučovaný způsob zápisu maker, s nímž jsme se podrobněji seznámili v předchozí části tohoto seriálu:

; zdrojový kód makra if-not
(defmacro if-not
    "Evaluates test. If logical false, evaluates and returns then expr, 
    otherwise else expr, if supplied, else nil."
    {:added "1.0"}
    ([test then]
        `(if-not ~test ~then nil))
    ([test then else]
        `(if (not ~test) ~then ~else)))

Dodejme jen, že test, then a else nejsou v tomto případě žádná klíčová slova, ale pouze názvy parametrů předávaných makru if-not při jeho volání (názvy parametrů nesmí být quotovány, proto jsou před nimi zapsány tildy).

Jednoduchý příklad použití tohoto makra:

user=> (if-not (zero? (- 1 1)) (println "nenulovy vysledek"))
nil
 
 
user=> (if-not (zero? (- 2 1)) (println "nenulovy vysledek"))
nenulovy vysledek
nil
 
 
; díky použití syntax-quote se rozepíše funkce not na plný název
user=> (macroexpand '(if-not (zero? (- 2 1)) (println "nenulovy vysledek")))
(if (clojure.core/not (zero? (- 2 1))) (println "nenulovy vysledek") nil)
 
 
user=>

5. Univerzální podmíněné provádění příkazů s využitím makra cond

Při popisu standardních maker jazyka Clojure nesmíme zapomenout na makro cond, které je nedílnou součástí mnoha programovacích jazyků odvozených od LISPu. Důvod pro tuto oblibu cond (ať již se jedná v konkrétní implementaci jazyka o makro či naopak o speciální formu) je prostý: v původním návrhu programovacího jazyka LISP byl tento jazyk kromě smyčky REPL doplněn o sedm základních funkcí a dvě speciální formy: atom, car, cdr, cond, cons, eq, quote, lambda a label.

Existence smyčky REPL a těchto sedmi speciálních forem/funkcí skutečně stačila pro vytvoření plnohodnotného (i když zpočátku ne příliš praktického) programovacího jazyka. V případě Clojure je situace vlastně zcela opačná, protože základní speciální formou používanou pro konstrukci podmínek, je speciální forma if, z níž je relativně snadné vytvořit makro cond. U některých implementací LISPu je tomu přesně naopak – základní speciální formou je zde cond a if je implementován jako makro.

Vraťme se však k makru cond použitém v programovacím jazyku Clojure. Toto makro akceptuje libovolný počet dvojic test-příkaz. Jednotlivé testy (jde samozřejmě o výrazy – formy) se postupně vyhodnocují a v případě, že se vyhodnotí na hodnotu true, vrátí makro cond hodnotu vyhodnoceného příkazu. V opačném případě se vyhodnotí další test atd. Pokud se ani jeden test nevyhodnotí na logickou hodnotu true, vrátí toto makro hodnotu nil. U makra cond je zajímavé prostudovat jeho stavbu, protože zde najdeme jak test na počet předávaných parametrů (musí být sudý, neboť jde vždy o dvojice test-příkaz), tak i rekurzi. Při rekurzivním volání makra se mu předají všechny původní parametry kromě prvních dvou (přesněji řečeno kromě první dvojice test-příkaz). Zkuste se sami zamyslet nad tím, kdy přesně k rekurzi dochází:

(defmacro cond
    "Takes a set of test/expr pairs. It evaluates each test one at a
    time.  If a test returns logical true, cond evaluates and returns
    the value of the corresponding expr and doesn't evaluate any of the
    other tests or exprs. (cond) returns nil."
    {:added "1.0"}
    [& clauses]
      (when clauses
        (list 'if (first clauses)
              (if (next clauses)
                  (second clauses)
                  (throw (IllegalArgumentException.
                           "cond requires an even number of forms")))
              (cons 'clojure.core/cond (next (next clauses))))))

Na příkladu použití makra cond je patrné, že velmi efektivním způsobem dokáže nahradit jak příkaz switch-case, tak i sekvenci příkazů if-elseif-elseif-else, které se mnohdy nevyhneme v jiných programovacích jazycích. Zajímavé je zde i použití :else, což je keyword (ty se zapisují s dvojtečkou před symbolem). Využívá se zde faktu, že if :keyword … vždy povede k vyhodnocení těla speciální formy if; ovšem skalní LISPaři pravděpodobně v poslední větvi cond použijí namísto testu přímo hodnotu true (v LISPu jen T):

; definice funkce, v níž je využito makro cond
(defn znamka
    [body]
    (cond
        (>= body 95) "A"
        (>= body 80) "B"
        (>= body 70) "C"
        (>= body 60) "D"
        (>= body 50) "E"
        :else "F"))
 
 
; test funkce znamka
user=> (znamka 0)
"F"
 
 
; test funkce znamka
user=> (znamka 50)
"E"
 
 
; test funkce znamka
user=> (znamka 90)
"B"
 
 
; test funkce znamka
user=> (znamka 100)
"A"
 
 
; složitější příklad
user=> (map znamka (range 0 101 10))
("F" "F" "F" "F" "F" "E" "D" "C" "B" "B" "A")
 
 
user=>

6. Makro while další poněkud skrytá „nefunkcionální“ řídicí konstrukce

Dalším standardním makrem, o němž se v dnešním článku zmíníme, je makro nazvané while. Asi správně uhodnete, že toto makro iterativně spouští (či lépe řečeno postupně vyhodnocuje) nějaké tělo smyčky, a to tak dlouho, dokud platí, že výraz zapsaný za while se vyhodnotí na pravdivostní hodnotu true. Povšimněte si, že se opět tiše předpokládá, že tělo smyčky bude mít nějaký vedlejší efekt jenž způsobí změnu hodnoty výrazu smyčky while (nejedná se tedy z pohledu funkcionálního programátora o příliš šťastně vytvořenou konstrukci). Typickým vedlejším efektem je nastavení hodnoty nějaké lokální či globální proměnné. Pravděpodobně taktéž uhodnete, jak je makro while interně implementováno – musí se v něm použít rekurze a to dokonce tail rekurze, která je v programovacím jazyce Clojure představována dvojicí loop-recur. Jak loop tak i recur jsou speciální formy tvořící základní jazykové konstrukce využitelné programátorem:

; definice makra while
(defmacro while
  "Repeatedly executes body while test expression is true. Presumes
  some side-effect will cause test to become false/nil. Returns nil"
  {:added "1.0"}
  [test & body]
  `(loop []
      (when ~test
          ~@body
          (recur))))

Demonstrační příklad bude asi dosti netypický:

user=> (while (> (Math/random) 0.1) (println "Stale pocitam"))
Stale pocitam
Stale pocitam
Stale pocitam
Stale pocitam
Stale pocitam
Stale pocitam
Stale pocitam
Stale pocitam
Stale pocitam
nil
 
 
user=>

Expanze výše vypsané „smyčky while“ vypadá takto:

user=> (macroexpand-1 '(while (> (Math/random) 0.1) (println "Stale pocitam")))
(clojure.core/loop
    []
    (clojure.core/when (> (Math/random) 0.1)
        (println "Stale pocitam") (recur)))
; (výstup byl zarovnán ručně)
 
 
user=>

7. Makro dotimes: další příklad použití tail rekurze v praxi

V některých typech aplikací může být poměrně užitečné použít makro nazvané jednoduše a přitom příhodně dotimes, které dokáže předaný výraz (formu) opakovat n krát. Přitom toto makro může v každé iteraci (opakování) nastavit zvolenou lokální proměnnou na aktuální hodnotu počitadla, přičemž se hodnota počitadla v první iteraci vždy nastavuje na nulu a v poslední iteraci dosahuje zadaného počtu opakování-1. Vzdáleně tedy můžeme toto makro považovat za ekvivalent programové smyčky for i in range(n): v programovacím jazyku Python či ekvivalent k počítané smyčce for (int i = 0; i<n; i++) známé z céčka (zde bez možnosti mít lokální proměnnou jako počitadlo), C++, Javy atd. Vzhledem k tomu, že se předpokládá, že forma – tělo smyčky – předaná makru dotimes bude mít nějaký vedlejší efekt, nejedná se sice o čistě funkcionální přístup, nicméně makro dotimes může být skutečně velmi užitečné, například při práci s poli (jejich použití v aplikaci je většinou diktováno snahou o dosažení větší efektivity programu).

; definice makra dotimes je na první pohled dosti komplikovaná
; (povšimněte si použití makra when uvnitř definice jiného makra)
(defmacro dotimes
    "bindings => name n
    Repeatedly executes body (presumably for side-effects) with name
    bound to integers from 0 through n-1."
    {:added "1.0"}
    [bindings & body]
    ; kontroly
    (assert-args
        (vector? bindings) "a vector for its binding"
        (= 2 (count bindings)) "exactly 2 forms in binding vector")
    ; vlastní výkonné tělo makra
    ; využívající dvojici lokálních proměnných i a n
    (let [i (first bindings)
          n (second bindings)]
        `(let [n# (long ~n)]
            (loop [~i 0]
                (when (< ~i n#)
                    ~@body
                    (recur (unchecked-inc ~i)))))))

Příklad použití makra dotimes jsme si již v tomto seriálu ukazovali:

(dotimes [i 10]
    (dotimes [j 10]
        (print (* (inc i) (inc j)) "\t"))
    (println))

A zde je již výsledek práce tohoto skriptu (poslední nil je návratovou hodnotou makra dotimes):

1     2     3     4     5     6     7     8     9     10
2     4     6     8     10    12    14    16    18    20
3     6     9     12    15    18    21    24    27    30
4     8     12    16    20    24    28    32    36    40
5     10    15    20    25    30    35    40    45    50
6     12    18    24    30    36    42    48    54    60
7     14    21    28    35    42    49    56    63    70
8     16    24    32    40    48    56    64    72    80
9     18    27    36    45    54    63    72    81    90
10    20    30    40    50    60    70    80    90    100
nil

Na expanzi výrazu:

(dotimes [i 10] (println i))

je patrné použití lokálních symbolů s jedinečným jménem:

user=> (macroexpand-1 '(dotimes [i 10] (println i)))
(clojure.core/let [n__4220__auto__ (clojure.core/long 10)]
    (clojure.core/loop
        [i 0]
        (clojure.core/when (clojure.core/< i n__4220__auto__)
            (println i)
            (recur (clojure.core/unchecked-inc i)))))
; (výstup byl zarovnán ručně)
 
 
user=>

8. Idiom with-* používaný v programovacích jazycích odvozených od LISPu

Při tvorbě reálných aplikací v programovacím jazyku Clojure se poměrně často setkáme s následujícím problémem: máme za úkol otevřít nějaký zdroj dat (databázi, soubor…), přečíst z tohoto zdroje data a posléze zdroj dat opět zavřít. Dalším praktickým problémem je nastavení přesnosti a zaokrouhlovacího režimu pro objekty typu BigDecimal, provedení nějaké matematické operace a následně obnovení původní přesnosti a zaokrouhlovacího režimu. Všechny tyto problémy tedy vyžadují, aby se provedla nějaká nastavovací operace, která většinou mění prostředí programu, posléze se provede vlastní výpočet/sekvence příkazů a nakonec se obnoví původní prostředí programu. Takto chápané operace se v programovacím jazyce Clojure poměrně často implementují s využitím maker, jejichž název začíná na with-. Příkladem může být makro with-precision pro dočasnou změnu přesnosti a zaokrouhlovacího režimu pro objekty typu BigDecimal (viz předchozí text):

user=> (with-precision 1 (/ 1M 3))
0.3M
 
 
user=> (with-precision 2 (/ 1M 3))
0.33M
 
 
user=> (with-precision 10 (/ 1M 3))
0.3333333333M
 
 
user=>

Příkladem takto pojatého makra je poměrně užitečné standardní makro with-out-str, které dokáže „zachytit“ všechna volání funkcí print a println. Řetězce, které by se pomocí těchto funkcí normálně vypsaly na standardní výstup, jsou namísto využity jako návratová hodnota makra:

user=> (with-out-str (print "Hello ") (print "world") (print '!))
"Hello world!"
 
 
user=> (def vystup (with-out-str (print "Hello ") (print "world") (print '!)))
#'user/vystup
 
 
user=> vystup
"Hello world!"
 
 
user=>

Jak již bylo řečeno v úvodním odstavci, pracují makra with- takovým způsobem, že dočasně změní prostředí programu. Nejinak je tomu i v případě makra with-out-str, kde se dočasně změní objekt navázaný na symbol *out*, jenž představuje standardní výstup, neboli v řeči Javy System.out. Symbol *out* je při provádění příkazů předaných makru přesměrován na novou instanci objektu java.io.StringWriter, který je po provedení těla převeden na řetězec s využitím funkce str:

(defmacro with-out-str
  "Evaluates exprs in a context in which *out* is bound to a fresh
  StringWriter.  Returns the string created by any nested printing
  calls."
  {:added "1.0"}
  [& body]
  `(let [s# (new java.io.StringWriter)]
      (binding [*out* s#]
          ~@body
          (str s#))))

Jediným neznámým symbolem je zde binding, což je další makro, které dokáže dočasně (v rámci provádění těla) navázat na nějaký symbol jinou hodnotu.

9. Odkazy na Internetu

  1. 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
  2. Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html
  3. Clojure Macro Tutorial (Part III: Syntax Quote)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html
  4. Tech behind Tech: Clojure Macros Simplified
    http://techbehindtech.com/2010/09/28/clo­jure-macros-simplified/
  5. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  6. Eulerovo číslo
    http://cs.wikipedia.org/wi­ki/Eulerovo_číslo
  7. List comprehension
    http://en.wikipedia.org/wi­ki/List_comprehension
  8. List Comprehensions in Clojure
    http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html
  9. Clojure Programming Concepts: List Comprehension
    http://en.wikibooks.org/wi­ki/Clojure_Programming/Con­cepts#List_Comprehension
  10. Clojure core API: for macro
    http://clojure.github.com/clo­jure/clojure.core-api.html#clojure.core/for
  11. cirrus machina – The Clojure for macro
    http://www.cirrusmachina.com/blog/com­ment/the-clojure-for-macro/
  12. Clojure.org: Clojure home page
    http://clojure.org/downloads
  13. Clojure.org: Vars and the Global Environment
    http://clojure.org/Vars
  14. Clojure.org: Refs and Transactions
    http://clojure.org/Refs
  15. Clojure.org: Atoms
    http://clojure.org/Atoms
  16. Clojure.org: Agents as Asynchronous Actions
    http://clojure.org/agents
  17. A Couple of Clojure Agent Examples
    http://lethain.com/a-couple-of-clojure-agent-examples/
  18. Clojure – Functional Programming for the JVM
    http://java.ociweb.com/mar­k/clojure/article.html
  19. Clojure quick reference
    http://faustus.webatu.com/clj-quick-ref.html
  20. 4Clojure
    http://www.4clojure.com/
  21. ClojureDoc
    http://clojuredocs.org/
  22. Clojure (Wikipedia EN)
    http://en.wikipedia.org/wiki/Clojure
  23. Clojure (Wikipedia CS)
    http://cs.wikipedia.org/wiki/Clojure
  24. Riastradh's Lisp Style Rules
    http://mumble.net/~campbe­ll/scheme/style.txt
  25. Dynamic Languages Strike Back
    http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html
  26. Scripting: Higher Level Programming for the 21st Century
    http://www.tcl.tk/doc/scripting.html
  27. Java Virtual Machine Support for Non-Java Languages
    http://docs.oracle.com/ja­vase/7/docs/technotes/gui­des/vm/multiple-language-support.html
  28. New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
    http://java.sun.com/develo­per/technicalArticles/Dyn­TypeLang/
  29. JSR 223: Scripting for the JavaTM Platform
    http://jcp.org/en/jsr/detail?id=223
  30. JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform
    http://jcp.org/en/jsr/detail?id=292
  31. Java 7: A complete invokedynamic example
    http://niklasschlimm.blog­spot.com/2012/02/java-7-complete-invokedynamic-example.html
  32. InvokeDynamic: Actually Useful?
    http://blog.headius.com/2007/01/in­vokedynamic-actually-useful.html
  33. A First Taste of InvokeDynamic
    http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html
  34. Java 6 try/finally compilation without jsr/ret
    http://cliffhacks.blogspot­.com/2008/02/java-6-tryfinally-compilation-without.html
  35. An empirical study of Java bytecode programs
    http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/
  36. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mobilefish.com/tu­torials/java/java_quickgu­ide_jvm_instruction_set.html
  37. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  38. Control Flow in the Java Virtual Machine
    http://www.artima.com/under­thehood/flowP.html
  39. Root.cz: Využití komprimovaných ukazatelů na objekty v JVM
    http://www.root.cz/clanky/vyuziti-komprimovanych-ukazatelu-na-objekty-v-nbsp-jvm/
  40. Root.cz: JamVM aneb alternativa k HotSpotu nejenom pro embedded zařízení a chytré telefony
    http://www.root.cz/clanky/jamvm-aneb-alternativa-k-hotspotu-nejenom-pro-embedded-zarizeni-tablety-a-chytre-telefony/
  41. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/VMSpec­TOC.doc.html
  42. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  43. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  44. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  45. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  46. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  47. BCEL Home page
    http://commons.apache.org/bcel/
  48. BCEL Manual
    http://commons.apache.org/bcel/ma­nual.html
  49. Byte Code Engineering Library (Wikipedia)
    http://en.wikipedia.org/wiki/BCEL
  50. Java programming dynamics, Part 7: Bytecode engineering with BCEL
    http://www.ibm.com/develo­perworks/java/library/j-dyn0414/
  51. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html
  52. BCEL Tutorial
    http://www.smfsupport.com/sup­port/java/bcel-tutorial!/
  53. ASM Home page
    http://asm.ow2.org/
  54. Seznam nástrojů využívajících projekt ASM
    http://asm.ow2.org/users.html
  55. ObjectWeb ASM (Wikipedia)
    http://en.wikipedia.org/wi­ki/ObjectWeb_ASM
  56. Java Bytecode BCEL vs ASM
    http://james.onegoodcooki­e.com/2005/10/26/java-bytecode-bcel-vs-asm/
  57. Bytecode Outline plugin for Eclipse (screenshoty + info)
    http://asm.ow2.org/eclipse/index.html
  58. aspectj (Eclipse)
    http://www.eclipse.org/aspectj/
  59. Aspect-oriented programming (Wikipedia)
    http://en.wikipedia.org/wi­ki/Aspect_oriented_program­ming
  60. AspectJ (Wikipedia)
    http://en.wikipedia.org/wiki/AspectJ
  61. EMMA: a free Java code coverage tool
    http://emma.sourceforge.net/
  62. Cobertura
    http://cobertura.sourceforge.net/
  63. FindBugs
    http://findbugs.sourceforge.net/
  64. GNU Classpath
    www.gnu.org/s/classpath/
  65. Java VMs Compared
    http://bugblogger.com/java-vms-compared-160/
  66. JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
    http://www.jcp.org/en/jsr/de­tail?id=223
  67. Scripting for the Java Platform
    http://java.sun.com/develo­per/technicalArticles/J2SE/Des­ktop/scripting/
  68. Scripting for the Java Platform (Wikipedia)
    http://en.wikipedia.org/wi­ki/Scripting_for_the_Java_Plat­form
  69. Java Community Process
    http://en.wikipedia.org/wi­ki/Java_Specification_Requ­est
  70. Java HotSpot VM Options
    http://www.oracle.com/technet­work/java/javase/tech/vmop­tions-jsp-140102.html
  71. Great Computer Language Shootout
    http://c2.com/cgi/wiki?Gre­atComputerLanguageShootout
  72. Java performance
    http://en.wikipedia.org/wi­ki/Java_performance
  73. Trying the prototype
    http://mail.openjdk.java.net/pi­permail/lambda-dev/2010-August/002179.html
  74. Better closures (for Java)
    http://blogs.sun.com/jrose/en­try/better_closures
  75. Lambdas in Java: An In-Depth Analysis
    http://www.infoq.com/articles/lambdas-java-analysis
  76. Class ReflectiveOperationException
    http://download.java.net/jdk7/doc­s/api/java/lang/Reflective­OperationException.html
  77. Scala Programming Language
    http://www.scala-lang.org/
  78. Run Scala in Apache Tomcat in 10 minutes
    http://www.softwaresecret­weapons.com/jspwiki/run-scala-in-apache-tomcat-in-10-minutes
  79. Fast Web Development With Scala
    http://chasethedevil.blog­spot.cz/2007/09/fast-web-development-with-scala.html
  80. Top five scripting languages on the JVM
    http://www.infoworld.com/d/developer-world/top-five-scripting-languages-the-jvm-855
  81. Proposal: Indexing access syntax for Lists and Maps
    http://mail.openjdk.java.net/pi­permail/coin-dev/2009-March/001108.html
  82. Proposal: Elvis and Other Null-Safe Operators
    http://mail.openjdk.java.net/pi­permail/coin-dev/2009-March/000047.html
  83. Java 7 : Oracle pushes a first version of closures
    http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/
  84. Groovy: An agile dynamic language for the Java Platform
    http://groovy.codehaus.org/Operators
  85. Better Strategies for Null Handling in Java
    http://www.slideshare.net/Step­han.Schmidt/better-strategies-for-null-handling-in-java
  86. Control Flow in the Java Virtual Machine
    http://www.artima.com/under­thehood/flowP.html
  87. Java Virtual Machine
    http://en.wikipedia.org/wi­ki/Java_virtual_machine
  88. ==, .equals(), compareTo(), and compare()
    http://leepoint.net/notes-java/data/expressions/22com­pareobjects.html
  89. New JDK7 features
    http://openjdk.java.net/pro­jects/jdk7/features/
  90. Project Coin: Bringing it to a Close(able)
    http://blogs.sun.com/darcy/en­try/project_coin_bring_clo­se
  91. CloseableFinder source code
    http://blogs.sun.com/darcy/re­source/ProjectCoin/Closea­bleFinder.java
  92. Joe Darcy blog about JDK
    http://blogs.sun.com/darcy
  93. Java 7 – more dynamics
    http://www.baptiste-wicht.com/2010/04/java-7-more-dynamics/
  94. New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
    http://java.sun.com/develo­per/technicalArticles/Dyn­TypeLang/index.html
Našli jste v článku chybu?

3. 10. 2012 17:01

To me tesi, spis jsem se bal, ze se Common Lispari ozvou s komentari typu "woe to uz mame v CL 20 let", coz by (vetsinou) i byla pravda.

Ad pocet pokracovani - popravde receno sam nevim, ale rekneme dalsi tri dily vyjdou urcite, potom bych rad pokracoval v necem dalsim souvisejicim s JVM (a taky konecne makl na jednom projektu v Clojure :)

2. 10. 2012 20:00

JS (neregistrovaný)

To by me taky zajimalo, chci si cely serial stahnout, takze bych rad vedel, az bude posledni dil.

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

DigiZone.cz: ČRo rozšiřuje DAB do Berouna

ČRo rozšiřuje DAB do Berouna

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Měšec.cz: Finančním poradcům hrozí vracení provizí

Finančním poradcům hrozí vracení provizí

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

Vitalia.cz: Říká amoleta - a myslí palačinka

Říká amoleta - a myslí palačinka

Vitalia.cz: Baletky propagují zdravotní superpostel

Baletky propagují zdravotní superpostel

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

Lupa.cz: Teletext je „internetem hipsterů“

Teletext je „internetem hipsterů“

Vitalia.cz: „Připluly“ z Německa a možná obsahují jed

„Připluly“ z Německa a možná obsahují jed

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

DigiZone.cz: ČT má dalšího zástupce v EBU

ČT má dalšího zástupce v EBU

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí