Obsah
1. Programovací jazyk Clojure 11: generátorová notace seznamu (list comprehension)
2. Jednoduché formy využívající makro for
3. Složitější formy využívající makro for
4. Nekonečné sekvence aneb návrat k línému vyhodnocování
5. Použití modifikátorů :while a :when v makru for
6. Práce s více generátory současně
7. Demonstrační příklad – výpis hodnot hracích karet
8. Praktický příklad – výpočet Eulerova čísla s využitím makra for
1. Programovací jazyk Clojure 11: generátorová notace seznamu (list comprehension)
V dnešní části seriálu o Javě a o virtuálním stroji Javy (JVM) se již pojedenácté vrátíme k popisu programovacího jazyka Clojure, který původně vznikl právě pro virtuální stroj Javy a později byl reimplementován i pro platformu .NET (resp. CLR) a v současnosti dokonce existuje i jeho varianta naprogramovaná v JavaScriptu. Dnes se budeme zabývat zejména popisem velmi užitečného makra for, s jehož využitím je možné i v Clojure používat takzvanou „generátorovou notaci seznamu“, což je poněkud nepřesně přeložený anglický termín „list comprehension“. O způsobu překladu tohoto termínu se vedly a pravděpodobně dodnes vedou poměrně vášnivé diskuse; já se zde budu držet překladu použitého v knize Ponořme se do Python(u) 3 (původně Dive Into Python 3)), kterou si můžete stáhnout na stránkách http://knihy.nic.cz/, popř. si zde objednat i papírovou verzi knihy.
S využitím generátorové notace seznamu je možné v programovacích jazycích, které tento zápis podporují, zapsat deklaraci vytvoření nového seznamu s využitím seznamu jiného, a to pomocí aplikace nějaké zvolené funkce na všechny prvky zdrojového seznamu. V mnoha programovacích jazycích je nutné pro generátorovou notaci seznamů používat zvláštní příkaz či deklaraci, tj. vlastně novou syntaktickou kategorii. Z těch známějších jazyků podporujících list comprehension se jedná například o Python, Haskell, Scala či Erlang. Programovací jazyk Clojure se však od těchto jazyků v podpoře pro generátorovou notaci seznamů liší, a to dokonce hned v několika ohledech. V Clojure se totiž nemusela zavádět žádná nová syntaxe, ale postačovalo vhodně naprogramovat makro (jeho kód je však poměrně dlouhý). Navíc je možné aplikovat zvolenou funkci nejenom na (konečný) seznam, ale na libovolnou (a to i nekonečnou) sekvenci, čímž ve výsledku můžeme taktéž získat nekonečnou sekvenci vyhodnocovanou líně (lazy sequence). Třetím rozdílem Clojure oproti jiným jazykům s podporou generátorových notací seznamů je to, že v Clojure je možné pracovat s libovolným množstvím zdrojových seznamů (přesněji řečeno sekvencí), což je téma šesté a sedmé kapitoly.
2. Jednoduché formy využívající makro for
Makro for, pomocí něhož je v jazyce Clojure implementována generátorová notace seznamů, má poměrně široké možnosti použití a při jeho zápisu lze dokonce použít i některé modifikátory, s nimiž se seznámíme v navazujících kapitolách. My však začneme náš popis velmi jednoduchými demonstračními příklady, které teprve později budeme rozšiřovat.
V prvním demonstračním příkladu je použit zdrojový (nepojmenovaný) seznam obsahující čtyři prvky, z něhož je s využitím makra for vytvořen nový seznam, který taktéž obsahuje čtyři prvky. Při vytváření nového seznamu se postupně na prvky zdrojového seznamu aplikovala funkce inc, která hodnotu každého prvku zvýšila o jedničku. Zajímavý je především způsob zápisu makra for, kde je v hranatých závorkách (tedy ve vektoru) nejprve uveden název lokální proměnné používané při výpočtu a za jménem proměnné je pak uveden zdrojový seznam. Apostrof před zdrojovým seznamem zabrání jeho vyhodnocení; pokud by zde nebyl uveden, došlo by k pokusu o zavolání funkce s názvem 1 s trojicí parametrů 2, 3 4. Posledním parametrem makra for je výraz (forma), jehož výsledek je použit pro konstrukci výsledného seznamu:
user=> (for [x '(1 2 3 4)] (inc x)) (2 3 4 5)
Zdrojový seznam samozřejmě může být navázán na nějakou proměnnou, což může vést k poněkud čitelnějšímu zápisu:
; vytvoření zdrojového seznamu user=> (def seznam '(1 2 3 4)) #'user/seznam ; použití zdrojového seznamu ve "for" user=> (for [x seznam] (inc x)) (2 3 4 5)
Lokální proměnnou x, která je postupně navazována na jednotlivé prvky zdrojového seznamu, je samozřejmě možné použít i ve složitějších výrazech; důležitý je pro nás pouze výsledek daného výrazu (jen minimálně se zde používají funkce s vedlejším efektem, i když i to je možné). V následujícím příkladu vznikne čtyřprvkový seznam obsahující numerické hodnoty typu zlomek (ratio):
user=> (for [x '(1 2 3 4)] (/ 1 x)) (1 1/2 1/3 1/4)
Namísto zdrojového seznamu je však v jazyce Clojure možné použít i jiný typ sekvence, například vektor:
user=> (for [x [10 20 30 40]] (/ 1 x)) (1/10 1/20 1/30 1/40)
(Připomeňme si, že u vektorů se nemusí použít apostrof pro zákaz jejich vyhodnocení).
3. Složitější formy využívající makro for
V úvodní kapitole jsme si řekli, že v programovacím jazyce Clojure se namísto zdrojového seznamu může použít libovolná sekvence, což jsme si vlastně již předvedli v předchozí kapitole použitím vektoru namísto seznamu. Snad nejtypičtějším generátorem sekvence je v Clojure funkce range, kterou můžeme v makru for využít na místě, kam jsme původně explicitně zapisovali zdrojový seznam či vektor:
user=> (for [x (range 1 10)] (/ 1 x)) (1 1/2 1/3 1/4 1/5 1/6 1/7 1/8 1/9)
Samozřejmě můžeme použít jakoukoli formu, jejímž výsledkem je sekvence, například kombinaci funkcí take a range:
user=> (for [x (take 10 (range))] (Math/sin x)) (0.0 0.8414709848078965 0.9092974268256817 0.1411200080598672 -0.7568024953079282 -0.9589242746631385 -0.27941549819892586 0.6569865987187891 0.9893582466233818 0.4121184852417566)
Sekvence, která je výsledkem zavolání makra for, se může zpracovat naprosto stejným způsobem, jako jiné sekvence. V následujícím demonstračním příkladu se všechny prvky vytvořené sekvence postupně sečtou s využitím funkce apply:
user=> (apply + (for [x '(1 2 3 4 5)] (/ 1 x))) 137/60
Zde se naopak výsledná sekvence setřídí:
user=> (sort (for [x [1 10 2 30 3 42]] (/ 10 x))) (5/21 1/3 1 10/3 5 10)
Makra for je samozřejmě možné libovolným způsobem zanořovat, i když čitelnost je v tomto případě již velmi malá:
user=> (for [x (for [x (range 1 10)] (inc x))] (* x 2)) (4 6 8 10 12 14 16 18 20)
V předchozím příkladu je nejprve na sekvenci vytvořenou funkcí (range 1 10), tj. na sekvenci:
(1 2 3 4 5 6 7 8 9)
postupně aplikována funkce inc, takže jako mezivýsledek vznikne sekvence:
(2 3 4 5 6 7 8 9 10)
Na tuto sekvenci, resp. přesněji řečeno na prvky této sekvence, je postupně aplikována funkce (* … 2), čímž již dostaneme kýžený výsledek:
(4 6 8 10 12 14 16 18 20)
4. Nekonečné sekvence aneb návrat k línému vyhodnocování
Zajímavé bude zjistit, kdy přesně vlastně k vytvoření výsledného seznamu dochází. K tomu můžeme použít funkci s vedlejším efektem – výpisem nějaké informace na standardní výstup. Tato funkce může vypadat následovně:
; funkce nejprve vypíše informaci na standardní výstup ; a posléze vrátí hodnotu svého parametru zvýšenou o jedničku user=> (defn increment [x] (println "Inkrementace cisla " x) (inc x)) #'user/increment ; test funkce increment user=> (increment 42) Inkrementace cisla 42 43
Pokud tuto funkci použijeme v makru for, můžeme získat základní informace o chování tohoto makra:
user=> (for [x '(1 2 3 4)] (increment x)) (Inkrementace cisla 1 Inkrementace cisla 2 2 Inkrementace cisla 3 3 Inkrementace cisla 4 4 5)
Na terminál se vypsal jak výsledek makra for, tedy seznam (2 3 4 5), tak i zprávy vypisované funkcí increment jako její vedlejší efekt. Stále však nevíme, kdy přesně se vlastně funkce increment bude volat. Zkusme tedy zakázat vyhodnocení výsledku makra for tak, že jeho výsledek uložíme do proměnné. Již z popisu líných sekvencí víme, že dokud nebudeme přistupovat k jednotlivým prvkům této proměnné, nemělo by dojít k vyhodnocení:
user=> (def result (for [x '(1 2 3 4)] (increment x))) #'user/result
Skutečně – získali jsme sice novou proměnnou nazvanou result, ale nic jiného se na terminál nevypsalo, tudíž ani prozatím nedošlo k zavolání funkce increment. Vyhodnocení vynutíme až tím, že se budeme snažit vypsat hodnotu proměnné result:
user=> result (Inkrementace cisla 1 Inkrementace cisla 2 2 Inkrementace cisla 3 3 Inkrementace cisla 4 4 5)
Jakmile jednou k vyhodnocení došlo, může Clojure již použít jednou vypočtené hodnoty výsledné sekvence:
user=> result (2 3 4 5) user=>
Vzhledem k tomu, že se prvky sekvence získané makrem for vyhodnocují až ve chvíli, kdy jsou skutečně zapotřebí, nemusíme se bát zavolat toho makro i ve chvíli, kdy se na jeho vstupu objevuje nekonečná sekvence. Takovou sekvenci lze v Clojure asi nejjednodušeji získat zavoláním funkce range bez parametrů:
(user=> (def result (for [x (range)] (/ 1 (inc x)))) #'user/result
Pokud se nebudeme snažit získat všechny prvky výsledné nekonečné sekvence, ale spokojíme se pouze s vybraným konečným počtem prvků, bude vše v pořádku:
user=> (take 10 result) (1 1/2 1/3 1/4 1/5 1/6 1/7 1/8 1/9 1/10)
5. Použití modifikátorů :while a :when v makru for
V makru for je možné kromě zadání jména lokální řídicí proměnné a zdrojové sekvence (či, jak uvidíme dále, několika sekvencí) používat i takzvané modifikátory :while a :when. Modifikátor :while slouží pro zastavení generování výsledné sekvence ve chvíli, kdy přestane platit zadaná podmínka. V následujícím demonstračním příkladu je sice zdrojová sekvence stoprvková, ovšem vytvořená sekvence bude mít pouze deset prvků:
user=> (for [x (range 100) :while (< x 10)] x) (0 1 2 3 4 5 6 7 8 9)
Z výše uvedeného popisu modifikátoru :while vyplývá, že se nemusíme bát použít nekonečnou zdrojovou sekvenci, a to ani v případě, že se bude výsledná sekvence vyhodnocovat:
user=> (for [x (range) :while (< x 10)] (* x x)) (0 1 4 9 16 25 36 49 64 81)
Podmínka uvedená za modifikátorem :while může mít podobu téměř jakékoli formy (výrazu) vracející pravdivostní hodnotu true či false. V následujícím příkladu se vypíšou faktoriály menší než 1000:
user=> (for [x (range 100) :while (< (fact x) 1000)] (fact x)) (1 1 2 6 24 120 720)
Popř. si můžeme dovolit i tento zápis:
user=> (for [x (range) :while (< (fact x) 1000)] (fact x)) (1 1 2 6 24 120 720)
Druhý modifikátor se jmenuje :when a pracuje spíše jako filtr, tj. určuje, pro které hodnoty řídicí proměnné se má zavolat funkce specifikovaná v makru for:
user=> (for [x (range 100) :when (< x 10)] x) (0 1 2 3 4 5 6 7 8 9)
Vzhledem k tomu, že :when pouze filtruje hodnoty, ale nezastavuje vytváření výsledné sekvence, musíme si dát pozor na nekonečné sekvence:
user=> (for [x (range) :when (< x 10)] x) ; nikdy neskončí
Někdy je však použití líně vyhodnocovaných nekonečných sekvencí možné, viz též tento příklad, kde se provedla ,„zarážka“ pomocí funkce take:
user=> (take 20 (for [x (range) :when (> (* x x) 3)] (* 2 x))) (4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42)
6. Práce s více generátory současně
V úvodní kapitole jsme si řekli, že makro for dokáže pracovat s více generátory (tj. s více zdrojovými sekvencemi) současně. Princip jeho práce se podobá funkci vnořených programových smyček typu „for“, samozřejmě s tím rozdílem, že makro for vyhodnocuje výslednou sekvenci líně. Podívejme se nyní, jak se vlastně makro for s více generátory zapisuje. Nejjednodušší způsob zápisu vypadá následovně:
user=> (for [x (range 1 10) y (range 1 10)] (* x y)) (1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81) user=>
Makro vytvořilo (línou) sekvenci obsahující 9×9=81 prvků, přičemž každý prvek byl získán vynásobením hodnoty dvou řídicích proměnných x a y, přičemž proměnná y byla měněná „rychleji“, tedy tak, jak jsme na to zvyklí i z vnořených programových smyček.
My ovšem můžeme taktéž vytvořit sekvenci obsahující dvojice, trojice atd. prvků. Postačuje jen vhodně upravit funkci volanou makrem for, například takovým způsobem, aby se vytvořit vektor obsahující dvojici čísel:
user=> (for [x (range 1 10) y (range 1 10)] [x y]) ( [1 1] [1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9] [2 1] [2 2] [2 3] [2 4] [2 5] [2 6] [2 7] [2 8] [2 9] [3 1] [3 2] [3 3] [3 4] [3 5] [3 6] [3 7] [3 8] [3 9] [4 1] [4 2] [4 3] [4 4] [4 5] [4 6] [4 7] [4 8] [4 9] [5 1] [5 2] [5 3] [5 4] [5 5] [5 6] [5 7] [5 8] [5 9] [6 1] [6 2] [6 3] [6 4] [6 5] [6 6] [6 7] [6 8] [6 9] [7 1] [7 2] [7 3] [7 4] [7 5] [7 6] [7 7] [7 8] [7 9] [8 1] [8 2] [8 3] [8 4] [8 5] [8 6] [8 7] [8 8] [8 9] [9 1] [9 2] [9 3] [9 4] [9 5] [9 6] [9 7] [9 8] [9 9]) user=>
Jednu sekvenci (seznam, množinu, vektor) lze v makru for použít i vícekrát, jednotlivé průchody sekvencí jsou na sobě nezávislé:
; sekvence použitá v makru for user=> (def my-sequence (range 1 5)) #'user/my-sequence ; sekvenci použijeme celkem třikrát user=> (for [x my-sequence y my-sequence z my-sequence] [x y z]) ([1 1 1] [1 1 2] [1 1 3] [1 1 4] [1 2 1] [1 2 2] [1 2 3] [1 2 4] [1 3 1] [1 3 2] [1 3 3] [1 3 4] [1 4 1] [1 4 2] [1 4 3] [1 4 4] [2 1 1] [2 1 2] [2 1 3] [2 1 4] [2 2 1] [2 2 2] [2 2 3] [2 2 4] [2 3 1] [2 3 2] [2 3 3] [2 3 4] [2 4 1] [2 4 2] [2 4 3] [2 4 4] [3 1 1] [3 1 2] [3 1 3] [3 1 4] [3 2 1] [3 2 2] [3 2 3] [3 2 4] [3 3 1] [3 3 2] [3 3 3] [3 3 4] [3 4 1] [3 4 2] [3 4 3] [3 4 4] [4 1 1] [4 1 2] [4 1 3] [4 1 4] [4 2 1] [4 2 2] [4 2 3] [4 2 4] [4 3 1] [4 3 2] [4 3 3] [4 3 4] [4 4 1] [4 4 2] [4 4 3] [4 4 4]) user=>
Samozřejmě, že i v případě použití více generátorů je možné využít modifikátory :while a :when, například následujícím způsobem:
user=> (for [x (range 1 10) y (range 1 10) :while (< y x)] [x y]) ( [2 1] [3 1] [3 2] [4 1] [4 2] [4 3] [5 1] [5 2] [5 3] [5 4] [6 1] [6 2] [6 3] [6 4] [6 5] [7 1] [7 2] [7 3] [7 4] [7 5] [7 6] [8 1] [8 2] [8 3] [8 4] [8 5] [8 6] [8 7] [9 1] [9 2] [9 3] [9 4] [9 5] [9 6] [9 7] [9 8] ) user=>
Poznámka: výpis je samozřejmě upraven ručně, aby bylo patrné, jakým způsobem je výsledná sekvence vytvořena, přesněji řečeno, zda modifikátor :while ovlivnil vnitřní či vnější „smyčku“.
7. Demonstrační příklad – výpis hodnot hracích karet
Podívejme se nyní na možná poněkud „praktičtější“ demonstrační příklad, v němž máme za úkol vypsat všech 52 karet francouzského typu. Celý příklad je možné zapsat pomocí jediné formy, ovšem pro větší přehlednost bude lepší, když si nejprve vytvoříme dvojici zdrojových sekvencí (konkrétně vektorů), přičemž první sekvence bude obsahovat čtyři symboly na kartách (znaky v Unicode) a druhá sekvence pak hodnoty karet:
; sekvence (vektor) obsahující symboly na kartách user=> (def card-symbols ['\u2660 '\u2665 '\u2666 '\u2663]) #'user/card-symbols ; sekvence (vektor) obsahující hodnoty karet user=> (def card-numbers [2 3 4 5 6 7 8 9 10 'J 'Q 'K 'A]) #'user/card-numbers
Nyní již můžeme s využitím makra for získat sekvenci obsahující dvojice symbol:hodnota:
user=> (def result (for [card-symbol card-symbols card-number card-numbers] [card-symbol card-number])) #'user/result
Následně je již možné karty vypsat, například aplikací funkce print na získanou sekvenci:
user=> (apply print result) [♠ 2] [♠ 3] [♠ 4] [♠ 5] [♠ 6] [♠ 7] [♠ 8] [♠ 9] [♠ 10] [♠ J] [♠ Q] [♠ K] [♠ A] [♥ 2] [♥ 3] [♥ 4] [♥ 5] [♥ 6] [♥ 7] [♥ 8] [♥ 9] [♥ 10] [♥ J] [♥ Q] [♥ K] [♥ A] [♦ 2] [♦ 3] [♦ 4] [♦ 5] [♦ 6] [♦ 7] [♦ 8] [♦ 9] [♦ 10] [♦ J] [♦ Q] [♦ K] [♦ A] [♣ 2] [♣ 3] [♣ 4] [♣ 5] [♣ 6] [♣ 7] [♣ 8] [♣ 9] [♣ 10] [♣ J] [♣ Q] [♣ K] [♣ A] nil
8. Praktický příklad – výpočet Eulerova čísla s využitím makra for
Abychom si ukázali jednu z možností praktického využití makra for v aplikacích, napíšeme s jeho pomocí program pro výpočet přibližné hodnoty Eulerova čísla, které tvoří základ přirozených logaritmů a má v matematice jako jedna ze základních konstant i mnoho dalších použití. Pro výpočet Eulerova čísla použijeme součet nekonečné číselné řady prvků s hodnotou 1/x!. Celý vzorec lze nalézt na stránce http://cs.wikipedia.org/wiki/Eulerovo_číslo ve formě druhé definice této konstanty.
Aby bylo možné provést součet prvků výše zmíněné nekonečné řady, musíme nejprve vytvořit funkci pro výpočet faktoriálu. Některé způsoby zápisu této funkce jsme si již ukazovali v předchozích částech tohoto seriálu – jednalo se jak o čistě rekurzivní zápis, tak i o zápis používající tail rekurzi, popř. programovou smyčku. Dnes se pro jednoduchost spolehneme na použití funkce apply, která bude aplikovat operaci násobení na aritmetickou řadu celých čísel od 1 do n (jedná se o pravděpodobně nejkratší zápis faktoriálu):
user=> (defn fact [n] (apply * (range 1 (inc n)))) #'user/fact
Námi vytvořenou funkci pro výpočet faktoriálu můžeme jednoduše otestovat, například její aplikací na vstupní hodnoty 0..10:
user=> (map fact (range 1 10)) (1 2 6 24 120 720 5040 40320 362880)
Funkci fact můžeme použít společně s makrem for pro vytvoření číselné řady obsahující hodnoty 1/x!, přičemž x leží ve zvoleném rozsahu (0..max):
user=> (for [x (range 0 10)] (/ 1 (fact x))) (1 1 1/2 1/6 1/24 1/120 1/720 1/5040 1/40320 1/362880)
Pro výpočet přibližné hodnoty Eulerova čísla nám již pouze postačí výsledné hodnoty sečíst, například takto:
user=> (apply + (for [x (range 0 10)] (/ 1 (fact x)))) 98641/36288
Zlomek, tj. numerická hodnota typu ratio, se na desetinné číslo převede s využitím konverzní funkce double:
user=> (double (apply + (for [x (range 0 10)] (/ 1 (fact x))))) 2.718281525573192
Tato hodnota již leží poměrně blízko k očekávané hodnotě konstanty e:
user=> (Math/E) 2.718281828459045
Při požadavku na vyšší přesnost výpočtu stačí jednoduše zvýšit počet členů řady, tj. upravit druhý parametr funkce (range).
Předchozí fragment programu pro výpočet Eulerova čísla si můžeme pro větší čitelnost rozepsat:
(defn fact [n] (apply * (range 1 (inc n)))) (double (apply + (for [x (range 0 10)] (/ 1 (fact x)))))
9. Odkazy na Internetu
- Eulerovo číslo
http://cs.wikipedia.org/wiki/Eulerovo_číslo - List comprehension
http://en.wikipedia.org/wiki/List_comprehension - List Comprehensions in Clojure
http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html - Clojure Programming Concepts: List Comprehension
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#List_Comprehension - Clojure core API: for macro
http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/for - cirrus machina – The Clojure for macro
http://www.cirrusmachina.com/blog/comment/the-clojure-for-macro/ - Clojure.org: Clojure home page
http://clojure.org/downloads - Clojure.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - A Couple of Clojure Agent Examples
http://lethain.com/a-couple-of-clojure-agent-examples/ - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc
http://clojuredocs.org/ - Clojure (Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - Riastradh's Lisp Style Rules
http://mumble.net/~campbell/scheme/style.txt - Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Java Virtual Machine Support for Non-Java Languages
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html - New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
http://java.sun.com/developer/technicalArticles/DynTypeLang/ - JSR 223: Scripting for the JavaTM Platform
http://jcp.org/en/jsr/detail?id=223 - JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform
http://jcp.org/en/jsr/detail?id=292 - Java 7: A complete invokedynamic example
http://niklasschlimm.blogspot.com/2012/02/java-7-complete-invokedynamic-example.html - InvokeDynamic: Actually Useful?
http://blog.headius.com/2007/01/invokedynamic-actually-useful.html - A First Taste of InvokeDynamic
http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html - Java 6 try/finally compilation without jsr/ret
http://cliffhacks.blogspot.com/2008/02/java-6-tryfinally-compilation-without.html - An empirical study of Java bytecode programs
http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/ - Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Root.cz: Využití komprimovaných ukazatelů na objekty v JVM
http://www.root.cz/clanky/vyuziti-komprimovanych-ukazatelu-na-objekty-v-nbsp-jvm/ - 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/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - BCEL Home page
http://commons.apache.org/bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - FindBugs
http://findbugs.sourceforge.net/ - GNU Classpath
www.gnu.org/s/classpath/ - Java VMs Compared
http://bugblogger.com/java-vms-compared-160/ - JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
http://www.jcp.org/en/jsr/detail?id=223 - Scripting for the Java Platform
http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/ - Scripting for the Java Platform (Wikipedia)
http://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform - Java Community Process
http://en.wikipedia.org/wiki/Java_Specification_Request - Java HotSpot VM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html - Great Computer Language Shootout
http://c2.com/cgi/wiki?GreatComputerLanguageShootout - Java performance
http://en.wikipedia.org/wiki/Java_performance - Trying the prototype
http://mail.openjdk.java.net/pipermail/lambda-dev/2010-August/002179.html - Better closures (for Java)
http://blogs.sun.com/jrose/entry/better_closures - Lambdas in Java: An In-Depth Analysis
http://www.infoq.com/articles/lambdas-java-analysis - Class ReflectiveOperationException
http://download.java.net/jdk7/docs/api/java/lang/ReflectiveOperationException.html - Scala Programming Language
http://www.scala-lang.org/ - Run Scala in Apache Tomcat in 10 minutes
http://www.softwaresecretweapons.com/jspwiki/run-scala-in-apache-tomcat-in-10-minutes - Fast Web Development With Scala
http://chasethedevil.blogspot.cz/2007/09/fast-web-development-with-scala.html - Top five scripting languages on the JVM
http://www.infoworld.com/d/developer-world/top-five-scripting-languages-the-jvm-855 - Proposal: Indexing access syntax for Lists and Maps
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001108.html - Proposal: Elvis and Other Null-Safe Operators
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000047.html - Java 7 : Oracle pushes a first version of closures
http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/ - Groovy: An agile dynamic language for the Java Platform
http://groovy.codehaus.org/Operators - Better Strategies for Null Handling in Java
http://www.slideshare.net/Stephan.Schmidt/better-strategies-for-null-handling-in-java - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Java Virtual Machine
http://en.wikipedia.org/wiki/Java_virtual_machine - ==, .equals(), compareTo(), and compare()
http://leepoint.net/notes-java/data/expressions/22compareobjects.html - New JDK7 features
http://openjdk.java.net/projects/jdk7/features/ - Project Coin: Bringing it to a Close(able)
http://blogs.sun.com/darcy/entry/project_coin_bring_close - CloseableFinder source code
http://blogs.sun.com/darcy/resource/ProjectCoin/CloseableFinder.java - Joe Darcy blog about JDK
http://blogs.sun.com/darcy - Java 7 – more dynamics
http://www.baptiste-wicht.com/2010/04/java-7-more-dynamics/ - New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html